变量可在常量表达式中使用的条件

Kry*_*n S 14 c++ language-lawyer

该代码在所有4大编译器上都可以正常编译,即使在 -pedantic

struct S
{
  constexpr S(int a) {}
};

constexpr int f(S a)
{
  return 1;
}

int main()
{
  int a = 0;
  S s(a);
  constexpr int b = f(s);
}
Run Code Online (Sandbox Code Playgroud)

但是,按照标准不应该这样...对吗?首先,s将无法在常量表达式 [expr.const] / 3中使用,因为它不满足成为constexpr,或,const以及枚举或整数类型的条件。

其次,它不是常量初始化的 [expr.const] / 2,因为由于对变量执行左值到右值转换,所以初始化的完整表达式不是常量表达式 [expr.const] / 10a) 在初始化构造函数的参数时不能在常量表达式中使用。

是否所有这些编译器都只是在省略构造函数参数的初始化,因为它没有副作用,并且是否符合标准(我99%的肯定不是,因为这样做的唯一方法是: make s constexpr,并将其传递const int给int声明的a 或a constexpr?

Sto*_*ica 10

我相信魔术师的s俩是的复制者S。您省略了它,因此在这里为您生成了默认值。现在它也是一个constexpr功能。

[class.copy.ctor](重点是我的)

12默认/未定义为删除的复制/移动构造函数在使用odr([basic.def.odr]), 需要进行常量评估([expr.const])或在以下情况时进行隐式定义:在首次声明后明确指定为默认值。[?注意:复制/移动构造函数是隐式定义的,即使实现取消了其odr-use([basic.def.odr],[class.temporary])。[?end note?] 如果隐式定义的构造函数可以满足constexpr构造函数([dcl.constexpr])的要求,则隐式定义的构造函数为constexpr。

副本c'tor的求值是否违反[expr.const] / 4中的任何要点?它不是。它不会在参数的任何成员上执行从左值到右值的转换(没有要对其执行转换)。它不会以任何要求引用在常量表达式中可用的方式使用其引用参数。因此,尽管不是直觉的,但我们确实得到了有效的常数表达式。

我们可以通过添加一个成员来验证以上内容S。

struct S
{
  int a = 1;  
  constexpr S(int a) {}
};  
Run Code Online (Sandbox Code Playgroud)

现在,副本c'tor试图访问一个不能在常量表达式中使用的对象作为其评估的一部分(通过所述参考)。所以确实,编译器会抱怨。

  • @KrystianS看起来像[\ [expr.const \] / 4](http://eel.is/c++draft/expr.const#4)并未说您不能*提及*一个不是可用于常量表达式中的常量表达式... (2认同)
  • @KrystianS-但是它并没有被使用。副本c'tor负责产生一个值,而它不会评估`s`。 (2认同)
  • @KrystianS参数是从参数初始化的,这个初始化是`constexpr`。这使表达式成为常数表达式。 (2认同)
  • @KrystianS-*请告诉我标准要求中的哪些内容? (2认同)
  • @StoryTeller @LF现在想通了。左值到右值的转换不会发生(通常不适用于类类型的对象),因为“ s”绑定到(复制构造函数的)引用,并且复制构造函数调用本身是一个常量表达式。 (2认同)