const

const常量是固定值,在程序执行期间不会改变。 常量就像是常规的变量,只不过常量的值在定义后不能进行修改。

const 并未区分出编译期常量和运行期常量,而只是保证程序运行时不直接被修改。

constexpr

constexpr常量表达式

常量表达式 是能在编译时求值的表达式,constexpr 对象不仅值不会改变,而且保证能够在编译期取得结果

const 和 constexpr 变量之间的主要区别在于:const 变量的初始化可以延迟到运行时,而 constexpr 变量必须在编译时进行初始化。所有 constexpr 变量均为常量,因此必须使用常量表达式初始化。

constexpr 限定在了编译期常量。所以在 constexpr 引入, const的职责被拆分出来一部分,只作可读(readonly)语义的保证,而常量(const)语义交给了 constexpr 负责。

constexpr函数

c++11中的 constexpr指定的函数返回值和参数都必须保证是字面值,而且必须有且只有一行代码。所以通常只能通过return 三目运算符+递归来计算返回的字面值。

constexpr int factorial_1(int n)
{
    return n > 0 ? n * factorial_1( n - 1 ) : 1;
}

c++11允许构造函数为constexpr,使得可以在编译时创建和初始化类的对象。

class Point {
public:
    constexpr Point(double xVal, double yVal) : x(xVal), y(yVal) {}
    constexpr double getX() const { return x; }
    constexpr double getY() const { return y; }
private:
    double x, y;
};

constexpr Point origin(0, 0);

c++14中则只要保证返回值和参数是字面值就行,函数的限制被放宽,允许更复杂的逻辑,如局部变量、循环、无返回值等。

constexpr int factorial_2(int n)
{
    int result = 1;
    for (int i = 1; i <= n; ++i)
        result *= i;
    return result;
}

c++17中lambda表达式可以被声明为constexpr。对于一个lambda而言,只要被捕获的变量是字面量类型(lieteral type),那么整个lambda也将表现为字面量类型。

constexpr auto square_lambda = [](int n) { return n * n; };

constexpr if语句

C++17 引入了 constexpr if,允许在编译时根据条件进行分支。

template<typename T>
constexpr auto get_value(T t) {
    if constexpr (std::is_pointer<T>::value) {
        return *t;
    } else {
        return t;
    }
}