为什么非静态数据成员不能成为constexpr?

Kno*_*abe 26 c++ constexpr c++11

这是有效的代码:

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 };
};
Run Code Online (Sandbox Code Playgroud)

但在这里我真的想申报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!
};
Run Code Online (Sandbox Code Playgroud)

如上所示,代码将无法编译.原因是(根据7.1.5/1),只能声明静态数据成员constexpr.但为什么呢?

Ide*_*Hat 22

想想是什么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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:所以下面有很多讨论回顾这里有几个隐含的问题.

"为什么我不能通过声明其成员是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 };
};
Run Code Online (Sandbox Code Playgroud)

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 };
};
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

虽然我认为你最好使用constexpr功能,可以在限制性非限制性方式中使用吗?

constexpr int bar(S s) { return s.xVal; }
Run Code Online (Sandbox Code Playgroud)