这是有效的代码:
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
const int xVal { 0 };
const int yVal { 0 };
};
但在这里我非常想宣布xVal
和yVal
constexpr
- 就像这样:
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 }; // error!
};
如上所述,代码不会编译。原因是(根据7.1.5 / 1),只能声明静态数据成员constexpr
。但为什么?
答案 0 :(得分:20)
考虑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;
}
编辑:所以下面有很多讨论回顾过这里有一些隐含的问题。
采用以下示例:
//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实例,我会用模板来做:
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; }