想想constexpr 的含义。这意味着我可以在编译时解析这个值。
因此,类的成员变量本身不能是constexpr...xVal所属的实例直到实例化时才存在!拥有xVal 的东西可能是constexp,这将使xVal 成为constexpr,但xVal 永远不可能是constexpr。
这并不意味着这些值不能是 const 表达式……事实上,类的 constexpr 实例可以将变量用作 const 表达式:
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
int xVal { 0 };
int yVal { 0 };
};
constexpr S s;
template <int f>//requires a constexpr
int foo() {return f;}
int main()
{
cout << "Hello World" << foo<s.xVal>( )<< endl;
return 0;
}
编辑:所以下面有很多讨论,回顾了这里有几个隐含的问题。
“为什么我不能通过将类的成员声明为 constexpr 来强制类的所有实例为 constexpr?”
举个例子:
//a.h
struct S;
struct A {std::unique_ptr<S> x; void Foo(); A();/*assume A() tries to instantiate an x*/}
//main.cpp
int main(int argc, char** argv) {
A a;
a->foo();
}
//S.h
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
constexpr int xVal { 0 }; // error!
constexpr int yVal { 0 };
};
A 和 S 的定义可能在完全不同的编译单元中,因此 S 必须是 constexpr 的事实可能要到链接时才能知道,尤其是在忘记 A 的实现的情况下。这种模棱两可的情况很难调试,也很难实现。更糟糕的是,S 的接口可以完全暴露在共享库、COM 接口等中......这可能会完全改变共享库的所有基础结构,这可能是不可接受的。
另一个原因是它的传染性。如果类的任何成员是 constexpr,则所有成员(及其所有成员)和所有实例都必须是 constexpr。采取以下场景:
//S.h
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
constexpr int xVal { 0 }; // error!
int yVal { 0 };
};
任何 S 实例都必须是 constexpr 才能独占持有 constexpr xval。 yVal 本质上变成了constexpr,因为xVal 是。没有技术编译器的原因你不能这样做(我不认为),但它感觉不像 C++。
“好的,但是我真的想创建一个类 constexpr 的所有实例。阻止我这样做的技术限制是什么”。
可能除了标准委员会之外没有其他人认为这是一个好主意。就我个人而言,我发现它的实用性很小……我真的不想定义人们如何使用我的课程,只是定义我的课程在他们使用它时的行为方式。当他们使用它时,他们可以将特定实例声明为 constexpr(如上)。如果我有一些我想要一个 constexpr 实例的代码块,我会用模板来做:
template <S s>
function int bar(){return s.xVal;}
int main()
{
cout << "Hello World" << foo<bar<s>()>( )<< endl;
return 0;
}
虽然我认为您最好使用一个 constexpr 函数,该函数既可以用于限制性方式,也可以用于非限制性方式?
constexpr int bar(S s) { return s.xVal; }