【发布时间】:2013-12-20 14:58:50
【问题描述】:
我的理解是 constexpr 类类型的全局变量几乎无法使用,因为
这样的对象必须在每个 TU 中定义,因为
constexpr不允许前向声明对象。-
默认链接为
static将导致在内联函数中命名对象(ODR 使用与否)违反 ODR,因为各自的inline定义将具有不同的含义。 -
声明为
extern constexpr,每个TU 有一个定义,如果对象是ODR 使用的,则会违反ODR 规则,当引用它时会发生这种情况。- 对隐式
this参数进行引用,即使成员函数未使用它。 - 如果您尝试通过引用传递对象,显然会发生这种情况。
- 如果您尝试按值传递对象也会发生这种情况,这会隐式使用复制或移动构造函数,根据定义,该构造函数通过引用传递。
- 如果一个对象被声明为
extern constexpr,即使没有使用 ODR,GCC 和 Clang 都会抱怨 ODR 违规(多个定义)。
- 对隐式
这一切都正确吗?有没有办法让 constexpr 全局类类型不包装在 inline 函数中?
【问题讨论】:
-
我相信你的第二点是错误的。使用常量的 value 并不会直接使用它。实际上,该标准使用具有内部链接的
constexpr变量(参见std::allocator_arg作为示例)。 ODR 不关心您在函数中为常量表达式使用什么 names。 -
@Simple 该函数将违反 ODR,而不是对象。两个 TU 中包含的同一标头中的
inline函数的两个定义必须满足 ODR 规则,其中一部分是每个名称必须引用同一个实体。std::allocator_arg可能会让用户陷入困境,但从inline函数打印其地址很容易暴露 UB。 -
如果您需要它的地址,那么显然您违反了 ODR,但您在使用非类类型时遇到了同样的问题。请参阅 3.2/2:名称显示为潜在求值表达式的变量是 odr-used,除非它是满足出现在常量表达式 (5.19) 中的要求和左值到右值转换 ( 4.1) 立即应用.
-
@Simple 查看子项目符号列表,了解悄悄获取地址的内容。这就是我为这个问题指定班级类型的原因;与非类类型不同,类类型的左值到右值转换意味着构造函数使用 ODR 并否定转义子句。
-
我不认为你关于
this的观点是正确的。参见 5.19/2 [expr.const]: this (5.1) 除非它作为后缀表达式出现在类成员访问表达式中,包括非静态成员函数体中隐式转换的结果 和:为文字类或 constexpr 函数调用除 constexpr 构造函数以外的函数。由于函数调用替换,通过引用传递给 constexpr 函数也不会使用它。不久前我有一个关于这一点的问题。
标签: c++ c++11 global constexpr one-definition-rule