7

如果我们有一个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),除了如果对象在 D 的所有定义中具有相同的文字类型,并且该对象使用常量表达式 (5.19) 初始化,则名称可以引用具有内部链接或没有链接的非易失性 const 对象,并且该对象不是 ODR 使用的,并且该对象在 D 的所有定义中具有相同的值

4

3 回答 3

4

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

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

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

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

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

struct widget { 
    std::vector<int> bars;

    widget : bars(foo) {}
};
于 2013-06-17T00:58:48.913 回答
1

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

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

因此,由于它不是 odr 使用的,因此 odr 规则不适用于它,3.2.4:

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

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

如果对象在 D 的所有定义中具有相同的文字类型 [yes, both int],则名称可以引用具有内部 [constexpr is internal] 的 const 对象 [yes, constexpr is const],并且该对象已初始化带有常量表达式[yes, 10],并且使用对象的值(但不是地址),并且对象在D的所有定义中具有相同的值[yes, 10]

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

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

于 2013-06-17T00:54:20.730 回答
0

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

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

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

于 2013-06-17T00:42:15.900 回答