EMCPP条款15:只要有可能使用constexpr,就使用它

YiQi 管理员

表面上看,constexpr 表示的是这样的值:它不仅是 const, 而且在编译阶段就已知。关千 constexpr 函数的结果,你既不能断定它是 const, 也不能假定其值在编译阶段就已知。

请注意,const 并未提供和 constexpr 同样的保证,因为 const 对象不一定经由编译期已知值来初始化。一言以蔽之,所有 constexpr 对象都是 const 对象,而并非所有的 const 对象都是 constexpr 对象。如果你想让编译器提供保证,让变量拥有一个值,用于要求编译期常量的语境,那么能达到这个目的的工具是 constexpr, 而非 const

constexpr 对象的使用场景中如果涉及 constexpr 函数,正确的理解方式是以下这样:

  • constexpr 函数可以用在要求编译期常量的语境中。在这样的语境中,若你传给一个 constexpr 函数的实参值是在编译期已知的,则结果也会在编译期间计算出来。如果任何一个实参值在编译期未知,则你的代码将无法通过编译。
  • 在调用 constexpr 函数时,若传入的值有一个或多个在编译期未知,则它的运作方式和普通函数无异,亦即它也是在运行期执行结果的计算。这意味着,如果函数执行的是同样的操作,仅仅应用的语境一个是要求编译期常量的,一个是用于所有其他值的话,那就不必写两个函数。 constexpr 函数就可以同时满足所有需求。

constexpr 函数仅限于传入和返回字面型别 ( literal type) ,意思就是这样的型别能够持有编译期可以决议的值。在 C++11 中,所有的内建型别,除了 void,都符合这个条件(C++14 中这个限制解除了)。但是用户自定义型别同样可能也是字面型别,因为它的构造函数和其他成员函数可能也是 constexpr 函数(C++14)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Point {
public:
constexpr Point(double xVal = 0, double yVal = 0) noexcept : x(xVal), y(yVal)
{}

constexpr double xValue() const noexcept { return x; }
constexpr double yValue() const noexcept { return y; }

constexpr void setX(double newX) noexcept { x = newX; }
constexpr void setY(double newY) noexcept { y = newY; }

private:
double x, y;
};

通常来说,constexpr 函数里是不允许有 I/O 语句的。

要点速记

  • constexpr 对象都具各 const 属性,并由编译期已知的值完成初始化。
  • constexpr 函数在调用时若传入的实参值是编译期已知的,则会产出编译期结果。
  • 比起非 constexpr 对象或 constexpr 函数而言,constexpr 对象或是 constexpr 函数可以用在一个作用域更广的语境中。
此页目录
EMCPP条款15:只要有可能使用constexpr,就使用它