以下内容是否真的违反了ODR?

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 );
}

This function violates the ODR ([basic.def.odr] §3.2/6 ) twice because neither of the constructor 2 arguments receives an lvalue-to-rvalue conversion. They are therefore passed by address, but the address depends on the TU because const (and constexpr) implies internal linkage.

我最初认为它确实有作用,但问题在于magic_number具有内部链接。由于它具有内部链接,它是否本质上将magic_number视为不同翻译单元中的不同变量,因此不是相同变量的多个定义? 有人能引用C ++标准的最新工作草案来明确说明吗?


我认为好的@potatoswatter(David Krauss)在这里是完全错误的。此外,声明“除非它是标量并且每个使用都被丢弃或经过lvalue-to-rvalue转换,否则无法在TUs之间共享编译时常量。”忽略了模板常量技术。这应该在这样的论文中提到,以显示数据的inline所需的必要机制已经就位。 - Cheers and hth. - Alf
@Cheersandhth.-Alf。他可能是在指旧版标准,或者我误解了他的写法,但为了澄清一下,上面的例子实际上并没有违反ODR规则,对吗?尽管任何具有内部链接的变量都不应与另一个具有内部链接的变量(即使名称相同)在不同的翻译单元中发生冲突,但我似乎找不到任何关于链接和定义的相关内容。 - JustinBlaber
我从T.C.的回答中看到,我误解了这个引用。我把它理解为适用于常量的使用,而实际上是关于inline函数有不同的定义。这相当微妙。 - Cheers and hth. - Alf
@Cheersandhth.-Alf 完全是我的错。我在引用论文后的简短介绍实际上是我的误解,可能会影响你的阅读。 - JustinBlaber
1个回答

8
问题出在make_magic函数上。根据[basic.def.odr]/p6规定,程序中可以有多个带外部链接的内联函数定义,只要每个定义出现在不同的翻译单元中,并且这些定义满足以下要求。对于一个名为D的实体,在多个翻译单元中定义,那么:
  • D的每个定义都必须由相同的标记序列组成;
  • D的每个定义中,按照3.4进行查找的相应名称应该引用在D的定义内部定义的实体,或者在重载解析(13.3)和部分模板特化匹配(14.8.3)之后引用相同的实体,除非名称可以引用所有D定义中具有相同字面类型的非易失性常量对象,且这些对象通过常量表达式(5.20)初始化,并且这些对象没有被odr使用,并且这些对象在所有D定义中具有相同的值;
  • [...]
因为piecewise_constructmagic_number具有内部链接,所以当在多个翻译单元中定义内联函数make_magic时,名称piecewise_constructmagic_number将引用不同的实体——TU 1的make_magic将引用TU 1的piecewise_constructmagic_number,而TU 2的make_magic将引用TU 2的piecewise_constructmagic_number。由于问题中tuple的构造函数通过引用方式接受参数,因此没有进行左值到右值转换,这些对象已被odr使用,第二个要求中的例外不适用,因此存在ODR违规。
(顺便提一下,std::tuple没有piecewise_construct构造函数,并且无论如何这样的构造函数都应该采用元组作为参数,而不是一个普通的int,但这与文献试图说明的观点无关。)

啊!我误解了他所写的内容。所以,如果您在源文件中编写一个非内联函数,该函数odr使用magic_number(即通过引用传递一个int),并且被不同的翻译单元调用,那么不会有问题,对吗?我的初始推理是,不同翻译单元中的magic_number的odr-use是一个问题,因为它有多个定义,但由于链接是内部的,它实质上被视为翻译单元之间的不同变量(即甚至可以在不同的翻译单元中为其赋予不同的值)。 - JustinBlaber
如果函数不是内联的(因此仅在一个TU中定义),那么就没问题了。"由于链接是内部的,因此在翻译单元之间实际上被视为不同的变量(即,您甚至可以在不同的翻译单元中为其赋予不同的值吗?)"这是正确的,而且您可以这样做。 - T.C.
这似乎非常奇怪,但澄清了我先入为主的误解。 - JustinBlaber

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接