7

这里

struct piecewise_construct_t {};
constexpr piecewise_construct_t piecewise_construct = {};

const int magic_number = 42;

inline std::tuple<int> make_magic() {
return std::tuple<int>( piecewise_construct, magic_number );
}

此函数违反了 ODR([basic.def.odr] §3.2/6 )两次,因为构造函数 2 参数都没有接收左值到右值的转换。因此它们通过地址传递,但地址取决于 TU,因为 const(和 constexpr)意味着内部链接。

我最初认为它确实如此,但问题是它magic_number具有内部联系。既然它具有内部链接,那么它是否本质上不会将magic_number它们视为不同翻译单元中的不同变量,因此不视为同一变量的多个定义?有人可以通过引用 C++ 标准的最新工作草案来指定这一点吗?

4

1 回答 1

8

问题出在make_magic. [basic.def.odr]/p6:

如果每个定义出现在不同的翻译单元中,并且定义满足以下要求,则程序中可以有多个定义...具有外部链接的内联函数(7.1.2)...。给定这样一个D在多个翻译单元中定义的实体,那么

  • 的每个定义D应由相同的标记序列组成;和
  • 在 的每个定义中D,根据 3.4 查找的对应名称应指在 的定义中定义的实体D,或应指同一实体,在重载决议 (13.3) 和部分模板特化 (14.8.3) 匹配之后),除非一个名称可以引用具有内部链接或没有链接的非易失性const对象,如果该对象在 的所有定义中具有相同的文字类型D,并且该对象使用常量表达式 (5.20) 进行初始化,并且该对象不是odr-used,并且该对象在D;的所有定义中具有相同的值 和
  • [...]

因为piecewise_constructmagic_number具有内部链接,当在多个翻译单元中定义内联函数时make_magic,名称piecewise_constructmagic_number引用不同的实体 - TU 1make_magic将引用 TU 1piecewise_constructmagic_number,而 TU 2make_magic将引用 TU 2piecewise_constructmagic_number。由于tupleat 的构造函数通过引用获取参数,因此不执行左值到右值的转换,对象是 odr-used,并且第二个项目符号中的异常不适用,并且您违反了 ODR。

(顺便说一句,std::tuple没有piecewise_construct构造函数,并且在任何情况下,这样的构造函数可能会将元组作为参数而不是普通int的,但这与论文试图提出的观点是正交的。)

于 2015-07-27T02:18:50.357 回答