constexpr
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++ version | Supported |
|---|---|
| C++11 | Simple constexpr functions (a single return statement) and constexpr variables. |
| C++14 | constexpr functions support multiple statements and loops. |
| C++17 | constexpr lambda |
| C++20 | consteval (must be executed at compile-time), enhanced constexpr |
| C++23 | constexpr 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
| aspect | const | constexpr |
|---|---|---|
| Meaning | Variable cannot be modified | Variables or functions can be evaluated at compile time. |
| initialization | Can be initialized at runtime | Must be initialized at compile time. |
| function | can only be applied to member functions | Functions can be executed at compile time. |
| Usage | Prevent variables from being modified | Compile-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.
| Keywords | Meaning | Typical scenarios |
|---|---|---|
constexpr | It can be evaluated at compile-time or called at runtime. | Universal compile-time functions and constant expressions |
consteval | Must be evaluated at compile time | Generate compile-time IDs, compile-time verification |
constinit | Ensuring 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.
| Example | Discusses what | Newly emerged syntax | Why write it this way | Precautions |
|---|---|---|---|---|
| Example 1 | constexpr vs const | constexpr int size = 10;, array size | constexpr 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 2 | constexpr functions | loops in constexpr functions | The 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 3 | constexpr used for static_assert | static_assert() | Compile-time checks directly fail the compilation. | The parameters for static_assert must be compile-time constants. |
| Example 4 | constexpr lambda | constexpr 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 5 | constexpr vs consteval | consteval | consteval 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.
使用建议
- 明确目标:在开始前确定您的具体需求,以便选择最合适的工具或教程。
- 充分利用资源:参考官方文档、教程和博客,这些资料能帮助您快速上手并解决问题。
- 实践应用:通过动手操作项目或编写代码来巩固学习成果,提升实际操作能力。
- 问题解决:遇到困难时,查阅参考资料或寻求社区支持,逐步培养独立解决问题的能力。
- 分享经验:完成项目后,可以撰写文章或博客分享心得,帮助其他学习者。
如果需要针对特定领域(如单片机、机器人或环境搭建)的进一步建议,请提供更多信息,我将为您细化内容。
- Use constexpr Whenever Possible: Move runtime calculations to compile-time for better program performance.
- constexpr functions work at both compile-time and runtime: no need to write two copies of the code.
- Compile-time checks with
static_assert: Very powerful when combined with constexpr functions. - constexpr is not "faster" magic: For small functions, the compiler already optimizes. But it's useful for scenarios like constant tables and precomputation.
- "Must consider consteval only at compile time": Prefer writing ordinary utility functions as constexpr for fewer restrictions.
Summary
- The variable
constexprmust be determined at compile time and can be used as an array size or template parameter. - The function
constexprcan be executed at compile time (when parameters are constexpr). constexprfunctions can also be invoked at runtime; onlyconstevalmust be invoked at compile time.constemphasizes "immutability," andconstexpremphasizes "compile-time evaluation."- Starting with C++17, lambdas can use
constexpr. static_assert+ constexpr functions = compile-time safety nets.