首页 > 编程笔记 > C++笔记 阅读:26

C++ constexpr用法详解(附带实例)

在编译时运算表达式可以改善执行时间,因为需要执行的代码少了,编译器可做额外的优化。

编译时常量不仅仅是字面量(如数字或字符串),也可以是函数执行的结果。如果函数的所有输入值(不管它们是参数、局部变量或全局变量)在编译时已知,则编译器可以执行该函数并可在编译时获取其值。

C++ 中的关键字 constexpr(constant expression 的简称)用于声明编译时常量对象和函数。

C++ constexpr的使用方式

使用 constexpr 关键字,当你想要:
1) 定义可在编译时运算的非成员函数:
constexpr unsigned int factorial(unsigned int const n)
{
    return n > 1 ? n * factorial(n-1) : 1;
}

2) 定义可在编译时执行的用来初始化 constexpr 对象的构造函数及编译时调用的成员函数:
class point3d
{
    double const x_;
    double const y_;
    double const 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_;}
};

3) 定义可在编译时被运算的变量:
constexpr unsigned int size = factorial(6);
char buffer[size] {0};
constexpr point3d p {0, 1, 2};
constexpr auto x = p.get_x();

深度剖析C++ constexpr

C++ 中,const 关键字用来声明变量运行时为常量,这意味着一旦初始化,它们不可被更改。

然而,运算常量表达式仍可能需要运行时计算。constexpr关键字用来声明编译时为常量的变量或可在编译时运行的函数。constexpr 函数和对象可替换宏和硬编码字面值,而不会有性能损失。

函数声明为 constexpr 并不意味着它通常在编译时进行运算。它只允许在编译时运算的表达式中使用该函数。这只有当函数的输入值均可在编译时运算时才会发生。

以下代码展示了同一函数的两次调用,第一次是在编译时,第二次是在运行时:
constexpr unsigned int size = factorial(6);
// compile time evaluation

int n;
std::cin >> n;
auto result = factorial(n);
// runtime evaluation

constexpr 的使用范围有一些限制。在 C++14 和 C++20 中,这些限制有所变化。为了保持合理的列表,这里只展示 C++20 中需要满足的要求:
1) constexpr 的变量必须满足以下要求:
2) constexpr的函数必须满足以下要求:
3) 除了前面函数的要求外,constexpr 的构造函数必须额外满足以下要求:
4) 除了之前函数的要求外,C++20 之后的 constexpr 析构函数,还必须额外满足以下要求:
constexpr 类型的函数不是隐式的 const(在 C++14 中),因此如果函数不修改对象逻辑状态,那么你需要显式地使用 const 说明符。然而,constexpr 类型的函数是隐式的 inline(内联)。

另外,声明为 constexpr 的对象隐式地为 const。以下两个声明是等价的:
constexpr const unsigned int size = factorial(6);
constexpr unsigned int size = factorial(6);

一些情况下你需要同时声明 constexpr 和 const,它们可能是声明的不同部分。在以下示例中,p 是 constexpr 指针,指向常量整型:
static constexpr int c = 42;
constexpr int const * p = &c;

引用变量也可以是 constexpr,当且仅当它们是静态存储周期对象或函数的别名。以下代码片段给出了一个示例:
static constexpr int const & r = c;
在此示例中,r 是一个 constexpr 引用,定义了编译时常量对象 c 的别名,c 则在前面的代码片段中定义。

相关文章