首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么非静态数据成员不能是constexpr?

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

Stack Overflow用户
提问于 2014-12-11 03:01:28
回答 1查看 28K关注 0票数 42

这是有效的代码:

代码语言:javascript
复制
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 };
};

但在这里,我真的想声明xValyVal constexpr--如下所示:

代码语言:javascript
复制
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。但是为什么呢?

EN

回答 1

Stack Overflow用户

发布于 2014-12-11 03:12:45

想一想constexpr是什么意思。这意味着我可以在编译时解析这个值。

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

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

代码语言:javascript
复制
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;
}

编辑:下面有很多讨论,回顾了这里有几个隐含的问题。

“为什么我不能通过将类的成员声明为常量表达式来强制类的所有实例都为常量表达式?”

下面是一个例子:

代码语言:javascript
复制
//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必须是常量link的事实可能要等到链接时才能知道,特别是如果忘记了A的实现。这种模棱两可的情况很难调试,也很难实现。更糟糕的是,S的接口可能会完全暴露在共享库中,COM接口,ect...This可能会完全改变共享库的所有基础设施,这可能是不可接受的。

另一个原因是这是多么具有传染性。如果一个类的任何成员都是常量表达式,那么所有成员(及其所有成员)和所有实例都必须是常量表达式。以以下场景为例:

代码语言:javascript
复制
//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 xvalyVal天生就变成了constexpr,因为xVal就是。没有编译器的技术原因,你不能这样做(我不认为),但它感觉不是很像C++。

“好吧,但我真的想让一个类的所有实例常量表达式。什么是技术限制,使我无法做到这一点”。

也许只有标准委员会认为这不是一个好主意。就我个人而言,我发现它的实用性很小……我真的不想定义人们如何使用我的类,只是定义当他们使用它时,我的类是如何行为的。当他们使用它时,他们可以将特定的实例声明为常量表达式(如上所述)。如果我有一些代码块,我想要一个constexpr实例,我会用一个模板来完成:

代码语言:javascript
复制
template <S s>
function int bar(){return s.xVal;}

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

   return 0;
}

不过,我认为你最好使用一个常量表达式函数,它可以在限制性和非限制性两种方式下使用?

代码语言:javascript
复制
constexpr int bar(S s) { return s.xVal; }
票数 37
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27408819

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档