C++ 为什么可以';非静态数据成员是否为constexpr?

C++ 为什么可以';非静态数据成员是否为constexpr?,c++,c++11,constexpr,C++,C++11,Constexpr,这是有效代码: 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和yValconstexpr——如下所示: struct S { constexpr S(int x, int y): xV

这是有效代码:

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
。但是为什么呢?

想想
constexpr
的意思。这意味着我可以在编译时解析这个值

因此,类的成员变量本身不能是
constepr
xVal
所属的实例直到实例化时才存在!拥有
xVal
的东西可能是
constexp
,这将使
xVal
a
constexpr
,但
xVal
本身永远不可能是
constexpr

这并不意味着这些值不能是常量表达式…事实上,类的constexpr实例可以将变量用作常量表达式:

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;
}
S的任何实例都必须是
constexpr
,才能以独占方式持有
constexpr
xval
yVal
固有地变成
constepr
,因为
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;
}

因为它们是在运行时初始化的成员变量,在初始化之前无法计算。@remyabel我相信为什么我不能有一个constexpr与为什么我不使用大括号初始化时会出现constexpr错误不同…@IdeaHat你读过答案了吗?@remyabel:这个问题完全不同。它与初始化静态数据成员无关。有没有办法消除我问题顶部的误导性链接?@knowitallnabe如果我将其标记为不具建设性,评论真空最终会到来并将所有评论吹走。我希望constexpr数据成员将生成一个类,其中所有实例都可以声明为constexpr。也就是说,在编译过程中,尝试创建具有非constexpr值的对象将被拒绝。@KnowItAllWannabe constexpr不是对如何使用某些内容的限制;相反,它是一种在只允许使用constexpr的地方使用它的许可。给定非constexpr参数的constexpr函数将在运行时运行,而不是在编译时运行……这是一件好事,因为我不想为每种情况重复代码(就像我以前不得不做的那样)。任何可以被实例化为constexpr的类都可以有非constexpr的实例(我需要做的就是调用新的实例)。这有意义吗?对于声明为
constexpr
的对象的可变数据成员,
constexpr
表示编译时已知的值,这甚至是有争议的<类型上的code>constexpr确实是一种限制;可以想象
constexpr
数据成员需要使用常量表达式初始化。也许,非静态数据成员的好处太小,或者违背了
constexpr
的初衷。@IdeaHat:这是有道理的,我也理解,但我认为在编译过程中确保类的所有实例都有已知的值也是有道理的。@KnowItAllWannabe我认为这是不可能的,而且,就/u/dyp而言,我看不到实用程序。要求所有对象都是constexpr感觉很像是singleton模式的所有错误……作为类的用户,它使我无法做很多事情,以便为我提供一个功能,而这对于我来说是一个很小的问题。
//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 };
};
template <S s>
function int bar(){return s.xVal;}

int main()
{
   cout << "Hello World" << foo<bar<s>()>( )<< endl; 

   return 0;
}
constexpr int bar(S s) { return s.xVal; }