C++ 变量在常量表达式中可用的条件
这段代码在所有big 4编译器上都能很好地编译,即使在C++ 变量在常量表达式中可用的条件,c++,language-lawyer,C++,Language Lawyer,这段代码在所有big 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); } 然而,根据标准,这不应该如此。。。正确的?首先,s在常量表达式中不可用,因为它不能满足constepr或const以及枚举或整数类型的条件 其
-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);
}
然而,根据标准,这不应该如此。。。正确的?首先,s
在常量表达式中不可用,因为它不能满足constepr
或const
以及枚举或整数类型的条件
其次,它不是常量初始化的,因为初始化的完整表达式不会是常量表达式,因为在初始化构造函数的参数时,在常量表达式中不可用的变量(a
)上执行左值到右值的转换
所有这些编译器都只是因为没有副作用而省略了构造函数参数的初始化,并且符合标准吗(我99%确定它不是,因为它这样做的唯一方法是使
s
constexpr
,并将声明为constexpr
的const int
或int
传递给它)?我相信这里魔术师的把戏是s
的副本。您省略了它,所以这里为您生成了一个默认的。现在它也是一个constepr
函数
[class.copy.ctor](强调我的)
默认的复制/移动构造函数,未定义为
当使用odr时([basic.def.odr]),会隐式定义deleted,
当需要进行常量求值时([expr.const]),或者
在第一次声明后显式默认[ 注:该
复制/移动构造函数是隐式定义的,即使实现
省略了它的odr用法([basic.def.odr],[class.temporary])- 尾注 ]
如果隐式定义的构造函数满足要求
对于constexpr构造函数([dcl.constexpr]),隐式定义
构造函数是constexpr
副本c'tor的计算是否与中的任何点冲突?它没有。它不会对参数的任何成员执行左值到右值的转换(没有可执行转换的对象)。它不以任何方式使用其引用参数,这将要求所述引用在常量表达式中可用。因此,我们确实得到了一个有效的常量表达式,尽管这是一个非直观的表达式
我们可以通过向S
添加一个成员来验证上述内容
struct S
{
int a = 1;
constexpr S(int a) {}
};
现在,复制者试图访问一个在常量表达式中不可用的对象,作为其计算的一部分(通过所述引用)因此,事实上,.Hm,你的推理至少听起来是合理的…你可能忽略的一点是,
f
根本不使用参数a
,因此结果在任何情况下都保持constexpr。如果我在这里,那么如果你将传递给S
的构造函数的参数存储在o被添加为成员变量并从f
中返回该变量。也许我读错了,但为什么会有a
的左值到右值转换?函数(包括构造函数)的参数仅隐式转换(包括值转换)如果需要。将非限定非引用int
传递给接受非限定非引用int
作为参数的函数根本不需要任何转换或转换,只需要值的普通副本。@Aconcagua正确,如果存储了值,则无法编译,但应初始化参数(标准不允许省略初始化)尽管如此,这种初始化并没有任何副作用。这可能会有一些影响。expr3:s没有使用。expr2:它是一个局部int。编译器在编译时知道这个值。编译器很聪明。@krystian看起来并没有说不能在常量表达式中的常量表达式中提到一个不可用的变量。。@krystian-但它不被使用。复制程序负责生成一个值,它这样做时不计算s
@krystian参数是从参数初始化的,这个初始化是constepr
。这使得表达式成为一个常量表达式。@krystian-标准的定义是什么t、 请问tell?@StoryTeller@L.F.现在就明白了。左值到右值的转换不会发生(对于类类型的对象通常不会发生),因为s
绑定到(复制构造函数的)引用,而复制构造函数调用本身是一个常量表达式。