C++ consteval用法详解(附带实例)
在 C++ 中,如果函数的所有输入在编译时可用,那么 constexpr 函数允许在编译时进行函数运算。然而,这不是一定的,constexpr 函数也可能在运行时执行。
consteval 是 C++20 中引入的一个关键字,用于强制函数在编译期间计算,确保函数在编译时产生常量表达式
1) 定义必须在编译时运算的非成员函数或函数模板:
2) 定义必须在编译时执行的用来初始化 constexpr 对象的构造函数及只在编译时调用的成员函数:
即时函数有以下规则:
如何使用 factorial() 函数如下所示:
然而,以下示例会产生编译错误,因为即时函数 factorial() 和 point3d 的构造函数无法在编译时进行运算:
除非即时函数在常量表达式里,否则无法对其取地址:
consteval 是 C++20 中引入的一个关键字,用于强制函数在编译期间计算,确保函数在编译时产生常量表达式
C++ consteval的使用方式
使用 consteval 关键字,当你想要:1) 定义必须在编译时运算的非成员函数或函数模板:
constexpr unsigned int factorial(unsigned int const n) { return n > 1 ? n * factorial(n-1) : 1; }
2) 定义必须在编译时执行的用来初始化 constexpr 对象的构造函数及只在编译时调用的成员函数:
class point3d { double x_; double y_; double z_; public: constexpr point3d(double const x = 0, double const y = 0, double const z = 0) : x_{x}, y_{y}, z_{z} {} constexpr double get_x() const {return x_;} constexpr double get_y() const {return y_;} constexpr double get_z() const {return z_;} };
深度剖析C++ consteval
consteval 说明符在 C++20 中引入。它只可用于函数或函数模板,并定义它们为即时函数。这意味着任何函数调用必须在编译时执行,并产生编译时常量表达式。如果函数不能在编译时进行运算,那么程序格式错误,编译器会报编译错误。即时函数有以下规则:
- 析构函数、分配、释放函数不能是即时函数;
- 如果函数声明包含 consteval 说明符,则所有那个函数的声明必须包含它;
- consteval 说明符不能和 constexpr 或 constinit 一起使用;
- 即时函数是内联 constexpr 函数。因此,即时函数和函数模板必须满足与 constexpr 函数相关的要求。
如何使用 factorial() 函数如下所示:
constexpr unsigned int f = factorial(6); std::cout << f << '\n'; constexpr point3d p {0, 1, 2}; std::cout << p.get_x() << ' ' << p.get_y() << ' ' << p.get_z() << '\n';
然而,以下示例会产生编译错误,因为即时函数 factorial() 和 point3d 的构造函数无法在编译时进行运算:
unsigned int n; std::cin >> n; const unsigned int f2 = factorial(n); // error double x = 0, y = 1, z = 2; constexpr point3d p2 {x, y, z}; // error
除非即时函数在常量表达式里,否则无法对其取地址:
using pfact = unsigned int(unsigned int); pfact* pf = factorial; constexpr unsigned int f3 = pf(42); // error constexpr auto addr_factorial() { return &factorial; } constexpr unsigned int invoke_factorial(unsigned int const n) { return addr_factorial()(n); } constexpr auto ptr = addr_factorial(); // ERROR: cannot take the pointer of an immediate function constexpr unsigned int f2 = invoke_factorial(5); // OK因为即时函数在运行时不可见,它们的符号没有生成,因此调试器无法显示它们。