【问题标题】:constexpr and ODRconstexpr 和 ODR
【发布时间】:2013-06-17 00:26:41
【问题描述】:

如果我们有一个头文件widget.hpp,内容如下:

constexpr int foo = 10;

struct widget
{
    int bars[foo];
};

...我们从两个源文件生成了两个翻译单元,它们都只包含widget.hpp,这是否违反了一个定义规则(更具体地说,使用foo 是否违反了一个定义规则)?

foo 具有内部链接,但它也是一个常量表达式。根据我对 C++11 标准中 3.2.6 的阅读(我将在下面引用),如果要求 #2 不仅仅指静态数据成员,则这是格式良好的。


3.2.6 要求 #2:

在D的每一个定义中,对应的名字,根据 3.4,应指在 D 的定义中定义的实体,或应指同一实体,在重载决议 (13.3) 和 在匹配部分模板特化 (14.8.3) 之后,except 名称可以引用具有内部或 如果对象在所有定义中具有相同的文字类型,则没有链接 的 D,并且对象用常量表达式(5.19)初始化, 并且该对象不是 odr-used,并且该对象在 D的所有定义

【问题讨论】:

    标签: c++ c++11 constexpr one-definition-rule


    【解决方案1】:

    我唯一可以看到关于您的案例有任何疑问的地方是您对foo 的使用是否符合odr-used 的条件。至少澄清意图的最简单方法可能是引用 n1337 的相应部分(立即遵循官方标准,主要是清理一些措辞,例如在这种情况下):

    [...] 如果对象在 D 的所有定义中具有相同的文字类型,并且该对象使用常量表达式(5.19)初始化,并且使用对象的值(但不是地址),并且该对象在D的所有定义中具有相同的值;

    您的使用显然符合所有这些要求。

    1. foo 在每种情况下都具有 int 类型。
    2. foo 使用常量表达式初始化。
    3. 您只使用foo 的值,而不是地址。
    4. foowidget 的所有定义中具有相同的值。

    也就是说,您最好将foos 改为std::vector

    struct widget { 
        std::vector<int> bars;
    
        widget : bars(foo) {}
    };
    

    【讨论】:

    • Jerry 你在检查他没有使用 foo 的指针;如果他之前在其他地方使用了 foo 的指针,那么他原来的语句还会被 odr-used 吗?
    【解决方案2】:

    至于foo的多重定义,我不认为foo是odr-used,因为它满足3.2.3中出现在常量表达式中的要求:

    变量 x 其名称显示为潜在求值表达式 ex 是 odr-used 除非 x 是满足出现在常量表达式中的要求的对象

    因此,由于它不是 odr-used,因此 odr-rule 不适用于它,3.2.4:

    每个程序都应该包含一个对每个非内联函数或 odr 使用的变量的定义 在那个程序中

    至于widget的两种不同定义,根据3.2.6是否足够相似。答案是肯定的,因为 N3485 3.2.6:

    如果在 D 的所有定义中对象具有相同的文字类型 [yes, both int] 和用常量表达式[yes, 10]初始化对象,使用对象的值(但不是地址),并且对象在D的所有定义中都具有相同的值[yes, 10]

    因此,即使名称 foo 指的是两个不同 TU 中的两个不同实体,这两个实体也满足给定的要求。

    (实际上它是有效的,因为编译器会将两个类布局相同,因此从两个 TU 生成的代码将是兼容的。)

    【讨论】:

      【解决方案3】:

      我不明白你的解释。引用的文本正确地适用于引用的示例。只要您在所有 TU 中都这样包含它。要违反 ODR,您必须破坏文本中的某些内容:

      constexpr double foo = 10; // type
      constexpr int foo = ret_10(); // non-const init
      constexpr int foo = 42; // value
      

      为了打破 ODR 的使用,我认为你必须获取它的地址。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-11-29
        • 2016-03-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-30
        • 1970-01-01
        • 2017-07-02
        相关资源
        最近更新 更多