为何非constexpr对象可调用constexpr operator()生成常量表达式?C++是否合规?
为什么非constexpr对象有时能用于编译期表达式?
先看第一个可编译的例子:
#include <array> struct Test { constexpr int operator()(int i) const { return i * 2; } }; int main() { Test test{}; std::array<int, test(10)> arr{}; }
这个代码能编译的核心原因是:Test没有非静态成员变量,它的operator()是constexpr,且计算逻辑只依赖传入的参数i,完全不依赖对象自身的状态。此时即便test不是constexpr对象,编译器也能判定test(10)是核心常量表达式——因为调用这个函数不需要访问任何运行时才能确定的状态,对象本身默认构造后没有需要初始化的成员,编译期就能直接算出结果20。这完全符合C++标准,标准允许在常量表达式中使用这类不依赖运行时状态的非constexpr对象。
再看第二个无法编译的例子:
struct Test { int member; constexpr Test(int member): member(member) {} constexpr int operator()(int i) const { return i * member; } }; int main() { /* constexpr */ Test test{10}; std::array<int, test(10)> arr{}; }
这里Test有成员变量member,operator()的计算依赖这个成员的值。如果test没有被声明为constexpr,编译器无法保证这个对象的member值在编译期是确定的——哪怕构造参数是字面量10,标准也要求必须显式用constexpr声明对象,才能确保它的状态是编译期常量。此时test(10)依赖非constexpr对象的成员,无法成为合法的常量表达式,自然不能作为std::array的模板参数(模板参数必须是编译期可求值的常量)。只有给test加上constexpr声明,编译器才能确认对象的状态在编译期完全确定,test(10)才能被当成常量表达式计算。
内容的提问来源于stack exchange,提问作者Mati
相关产品推荐
相关产品推荐

