[英]Static constexpr odr-used or not?
为什么下面的内容适用于gcc
但不适用于clang
,( 请看实时 ):
constexpr int giveMeValue() { return 42; }
struct TryMe {
static constexpr int arr[1] = {
giveMeValue()
};
};
int main() {
int val = TryMe::arr[0];
return val;
}
我得到一个未解决的外部符号与clang。
TryMe::arr[0]
是一个对象吗? 如果是的话,它是否经常使用?
TryMe::arr
是odr,但是你没有提供定义( 请看实时 ):
constexpr int TryMe::arr[1];
为什么gcc
和clang
之间的结果不一致? 这是因为从C ++ 11和C ++ 14草案标准( 强调我的 )开始,odr违规不需要断言:
每个程序应该只包含该程序中使用的每个非内联函数或变量的一个定义; 无需诊断 。
我们可以看到它在C ++ 11标准草案第3.2
节中使用了它,它说:
除非是未评估的操作数(第5条)或其子表达式,否则可能会对表达式进行求值。 名称显示为潜在评估表达式的变量是odr-used,除非它是满足出现在常量表达式(5.19)中的要求的对象,并且立即应用左值到右值转换(4.1)。
TryMe::arr
是一个对象,它确实满足出现在常量表达式中的要求,但是左值到右值的转换不是立即应用于TryMe::arr
而是应用于TryMe::arr[0]
。
C ++ 14标准草案中更新的措辞,适用于C ++ 11,因为它是通过缺陷报告( DR 712 )应用的:
变量x的名称显示为潜在评估的表达式ex,除非将lvalue-to-rvalue转换(4.1)应用于x,否则将生成一个不调用任何非平凡函数的常量表达式(5.19),并且如果x是一个对象,ex是表达式e的潜在结果集合的元素,其中左值到右值的转换(4.1)应用于e,或者e是丢弃值表达式
表达式TryMe::arr[0]
的潜在结果在3.2
段第2
段中的标准是空的,因此它使用的是odr。
注意:您需要在类9.4.2
[class.static.data]中提供类之外的定义,其中说明( 强调我的 ):
可以使用constexpr说明符在类定义中声明文字类型的静态数据成员; 如果是这样,它的声明应指定一个大括号或等于初始化器,其中作为赋值表达式的每个initializer子句都是一个常量表达式。 [注意:在这两种情况下,成员可能会出现在常量表达式中。 -end note] 如果程序中使用了odr-used(3.2) ,并且命名空间作用域定义不包含初始化程序,则仍应在名称空间作用域中定义该成员
更新
TC指出了缺陷报告1926 ,它将以下子弹添加到3.2
[basic.def.odr]第2段:
- 如果e是带有数组操作数的下标操作(5.2.1 [expr.sub]),则该集合包含该操作数。
这意味着对数组进行下标不再是一种使用,因此OP代码在C ++ 1z中将很好地形成,并且它看起来像C ++ 14,因为缺陷看起来像是反对C ++ 14。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.