第 18.7 節

constexpr

0瀏覽次數0訪問次數--跳出率--平均停留

What problem does this section solve?

Some computations are known at compile time, but ordinary functions would calculate them at runtime—wasting CPU time. Additionally, certain scenarios (array size, template parameters, static_assert) require compile-time constants, which ordinary variables cannot provide.

constexpr allows functions and variables to be evaluated at compile time, shifting runtime overhead to compile time, and can also be used where "compile-time constants" are required.

What is this feature?

constexpr declares that a variable or function can be evaluated at compile time. Introduced starting with C++11, this feature has been enhanced in subsequent standards.

C++ versionSupported
C++11Simple constexpr functions (a single return statement) and constexpr variables.
C++14constexpr functions support multiple statements and loops.
C++17constexpr lambda
C++20consteval (must be executed at compile-time), enhanced constexpr
C++23constexpr supports more standard libraries

C++ standard version

C++11 (with each subsequent version bringing further enhancements)

Required header files

No additional header files are required. constexpr is a language keyword.

Basic Syntax

// constexpr 变量:值在编译期确定
constexpr int size = 100;

// constexpr 函数:可以在编译期执行
constexpr int square(int n)
{
    return n * n;
}

// constexpr 变量可以用编译期函数初始化
constexpr int val = square(5);  // 编译期计算

// C++20 consteval:必须在编译期执行(不能运行时调用)
consteval int cube(int n)
{
    return n * n * n;
}

const vs constexpr

aspectconstconstexpr
MeaningVariable cannot be modifiedVariables or functions can be evaluated at compile time.
initializationCan be initialized at runtimeMust be initialized at compile time.
functioncan only be applied to member functionsFunctions can be executed at compile time.
UsagePrevent variables from being modifiedCompile-time computation to improve efficiency
Here is the translation of the provided Simplified Chinese Markdown fragment into natural American English, following all specified rules.

Example|const int x = get_value();|constexpr int x = 5 * 3;|

Differences between constexpr, consteval, and constinit

These three terms may seem related to "constants," but they solve different problems. When starting out, master constexpr first, then move on to understanding C++20's consteval and constinit.

KeywordsMeaningTypical scenarios
constexprIt can be evaluated at compile-time or called at runtime.Universal compile-time functions and constant expressions
constevalMust be evaluated at compile timeGenerate compile-time IDs, compile-time verification
constinitEnsuring static objects are initialized at compile time, but the objects are not necessarily const.Avoid issues with dynamic initialization order of global variables

A one-sentence distinction: constexpr leans toward "whether it can be computed," consteval leans toward "must be computed now," constinit leans toward "initialization timing must be early."

Example code

Example 1: constexpr variables—must be determined at compile time

#include <iostream>

int main()
{
    constexpr int size = 10;        // 编译期常量
    int arr[size];                  // ✅ 可以用作数组大小

    const int runtime_size = size;  // const 可以用编译期常量初始化
    int arr2[runtime_size];         // ✅ 也可以用作数组大小(因为初始化值是 constexpr)

    int n = 5;
    // constexpr int s2 = n;        // ❌ n 是运行时变量,不能初始化 constexpr
    const int s3 = n;               // ✅ const 可以在运行时初始化
    // int arr3[s3];                // ❌ s3 不是编译期常量,不能用作数组大小

    std::cout << "size = " << size << "\n";

    return 0;
}

Results

size = 10

Example 2:Building on Example 1,constexpr 函数

#include <iostream>

// constexpr 函数:编译期可执行
constexpr int factorial(int n)
{
    int result = 1;
    for (int i = 1; i <= n; ++i)  // C++14 起支持循环
    {
        result *= i;
    }
    return result;
}

int main()
{
    // 编译期计算:factorial(5) 在编译时就得到 120
    constexpr int f5 = factorial(5);
    std::cout << "factorial(5) = " << f5 << "\n";

    // 也可运行时调用
    int n;
    std::cout << "Enter a number: ";
    std::cin >> n;
    std::cout << "factorial(" << n << ") = " << factorial(n) << "\n";

    return 0;
}

Results

factorial(5) = 120
Enter a number: 4
factorial(4) = 24

Example 3: Building on Example 2, constexpr for templates and compile-time checks

#include <iostream>

// constexpr 函数:编译期判断是否为质数
constexpr bool is_prime(int n)
{
    if (n <= 1) return false;
    for (int i = 2; i * i <= n; ++i)
    {
        if (n % i == 0) return false;
    }
    return true;
}

// 编译期静态断言
static_assert(is_prime(2), "2 is prime");
static_assert(is_prime(7), "7 is prime");
static_assert(!is_prime(9), "9 is NOT prime");

// 编译期生成质数数组
constexpr int get_nth_prime(int n)
{
    int count = 0;
    int num = 1;
    while (count < n)
    {
        ++num;
        if (is_prime(num))
        {
            ++count;
        }
    }
    return num;
}

int main()
{
    constexpr int primes[] = {
        get_nth_prime(1),  // 2
        get_nth_prime(2),  // 3
        get_nth_prime(3),  // 5
        get_nth_prime(4),  // 7
        get_nth_prime(5)   // 11
    };

    std::cout << "First 5 primes: ";
    for (int p : primes)
    {
        std::cout << p << " ";
    }
    std::cout << "\n";

    return 0;
}

Results

First 5 primes: 2 3 5 7 11 

Example 4: C++17 constexpr lambda

#include <iostream>

int main()
{
    // constexpr lambda:编译期可调用
    constexpr auto square = [](int x) constexpr {
        return x * x;
    };

    constexpr int result = square(5);  // 编译期计算
    std::cout << "square(5) = " << result << "\n";

    // constexpr lambda 也可运行时调用
    int n = 7;
    std::cout << "square(" << n << ") = " << square(n) << "\n";

    return 0;
}

Results

square(5) = 25
square(7) = 49

Example 5: Building on Example 4, constexpr can be called at runtime, whereas consteval cannot.

#include <iostream>

constexpr int square(int x)
{
    return x * x;
}

consteval int compile_time_square(int x)
{
    return x * x;
}

int main()
{
    constexpr int a = square(5);              // 编译期计算
    int n = 7;
    int b = square(n);                        // 运行期调用,也允许

    constexpr int c = compile_time_square(6); // 必须编译期计算
    // int d = compile_time_square(n);        // ❌ 编译错误:n 不是编译期常量

    std::cout << "a = " << a << "\n";
    std::cout << "b = " << b << "\n";
    std::cout << "c = " << c << "\n";

    return 0;
}

Results

a = 25
b = 49
c = 36

runtime results

See the "running results" for each example above.

Key syntax explanation in the example

|Here is the translation of the provided Simplified Chinese Markdown fragment into natural American English, following all specified rules.


ExampleDiscusses whatNewly emerged syntaxWhy write it this wayPrecautions
Example 1constexpr vs constconstexpr int size = 10;, array sizeconstexpr must be initialized at compile time and can be used as array size.A const can be initialized at runtime, but it is not guaranteed to be determined at compile time.
Example 2constexpr functionsloops in constexpr functionsThe same function can be invoked both at compile time and at runtime.All parameters must also be compile-time constants when called at compile time.
Example 3constexpr used for static_assertstatic_assert()Compile-time checks directly fail the compilation.The parameters for static_assert must be compile-time constants.
Example 4constexpr lambdaconstexpr auto f = [](int x) constexpr {...};Lambdas can also be evaluated at compile time.Supported since C++17, both constexpr keywords need to be written.
Example 5constexpr vs constevalconstevalconsteval functions can only be called at compile time.Only available in C++20

Common Errors

Error 1: Assigning a runtime variable to constexpr

int n = 5;
constexpr int x = n;  // ❌ n 不是编译期常量

The correct approach: const int x = n; (using const instead of constexpr).

Error 2: constexpr functions assume all cases can be evaluated at compile time

constexpr int divide(int a, int b)
{
    return a / b;  // 编译期 b=0 会导致编译错误
}
constexpr int x = divide(10, 0);  // ❌ 编译错误!

Correct practice: ensure parameter legality when calling at compile time.

Error 3: Undefined behavior inside a constexpr function

constexpr int get(int* p)
{
    return *p;  // 编译期不能解引用空指针
}
constexpr int x = get(nullptr);  // ❌ 编译错误!

The correct approach: Avoid undefined behavior in constexpr functions.

Error 4: Assuming that constexpr functions always execute at compile time

constexpr int square(int x) { return x * x; }

int n = 5;
int y = square(n);  // ✅ 这是运行期调用,不是编译期调用

Correct approach: When forcing compile-time, place the result in variables constexpr, static_assert, or template parameters; starting from C++20, you can also use the consteval function.

使用建议

  • 明确目标:在开始前确定您的具体需求,以便选择最合适的工具或教程。
  • 充分利用资源:参考官方文档、教程和博客,这些资料能帮助您快速上手并解决问题。
  • 实践应用:通过动手操作项目或编写代码来巩固学习成果,提升实际操作能力。
  • 问题解决:遇到困难时,查阅参考资料或寻求社区支持,逐步培养独立解决问题的能力。
  • 分享经验:完成项目后,可以撰写文章或博客分享心得,帮助其他学习者。

如果需要针对特定领域(如单片机、机器人或环境搭建)的进一步建议,请提供更多信息,我将为您细化内容。

  1. Use constexpr Whenever Possible: Move runtime calculations to compile-time for better program performance.
  2. constexpr functions work at both compile-time and runtime: no need to write two copies of the code.
  3. Compile-time checks with static_assert: Very powerful when combined with constexpr functions.
  4. constexpr is not "faster" magic: For small functions, the compiler already optimizes. But it's useful for scenarios like constant tables and precomputation.
  5. "Must consider consteval only at compile time": Prefer writing ordinary utility functions as constexpr for fewer restrictions.

Summary

  • The variable constexpr must be determined at compile time and can be used as an array size or template parameter.
  • The function constexpr can be executed at compile time (when parameters are constexpr).
  • constexpr functions can also be invoked at runtime; only consteval must be invoked at compile time.
  • const emphasizes "immutability," and constexpr emphasizes "compile-time evaluation."
  • Starting with C++17, lambdas can use constexpr.
  • static_assert + constexpr functions = compile-time safety nets.
音乐页