[basic.def.odr]/3提到了“非平凡函数”的术语,我在标准中找不到它的定义(N4140)。
[basic.def.odr]/3
变量x在一个潜在求值的表达式中出现,并且应用左值到右值转换(4.1)将x转换为一个不调用任何非平凡函数的常量表达式(5.19),或者如果x是一个对象,则ex是表达式e的可能结果集合的元素之一,其中要么对e应用左值到右值转换(4.1),要么e是一个废弃值表达式(第5条)。这时变量x被odr使用。
[basic.def.odr]/3提到了“非平凡函数”的术语,我在标准中找不到它的定义(N4140)。
[basic.def.odr]/3
变量x在一个潜在求值的表达式中出现,并且应用左值到右值转换(4.1)将x转换为一个不调用任何非平凡函数的常量表达式(5.19),或者如果x是一个对象,则ex是表达式e的可能结果集合的元素之一,其中要么对e应用左值到右值转换(4.1),要么e是一个废弃值表达式(第5条)。这时变量x被odr使用。
struct C
{
int l;
constexpr C(int _l) : l(_l) { }
constexpr C(const C&c) : q(c.l * 2) { }
};
int main()
{
constexpr C c{42};
constexpr int m = c.l;
struct K
{
int foo() { return c.l; }
}
K l;
return l.foo();
}
如果您查看标准中的以下行:
将 lvalue-to-rvalue 转换(4.1)应用于 x 会产生一个常量表达式(5.19),该表达式不调用任何非平凡函数
这里 c
满足出现在常量表达式中的要求,但是将 lvalue-to-rvalue 转换应用于 a 会调用一个非平凡函数。
为什么会调用一个非平凡函数?
当 lvalue-to-rvalue 转换发生在未评估的操作数或其子表达式中时,不访问所引用对象中包含的值。否则,如果 glvalue 具有类类型,则转换从 glvalue 复制初始化类型为 T
的临时对象,并且转换的结果是临时对象的 prvalue。
因此,使用类 C
的复制构造函数创建了一个 prvalue,由于复制构造函数是用户定义的,它是非平凡的,因此 c 在此处没有 ODR-used。
如果类 X 的复制/移动赋值运算符不是用户提供的,其参数类型列表等效于隐式声明的参数类型列表,则该运算符是平凡的。