headers 中的 `const` 和 `constexpr` 变量是否应该是 `inline` 以防止 ODR 违规?

Should `const` and `constexpr` variables in headers be `inline` to prevent ODR violations?

考虑以下 header 并假设它在多个 TU 中使用:

static int x = 0;

struct A {
    A() {
        ++x;
        printf("%d\n", x);
    }
};

正如 this question 所解释的,这是 ODR 违规,因此,UB。

现在, 如果我们的 inline 函数引用了一个非 volatile const object 而我们不 odr-use 它在那个函数中(加上其他规定),所以这在 header:

中仍然可以正常工作
constexpr int x = 1;

struct A {
    A() {
        printf("%d\n", x);
    }
};

但如果我们碰巧 odr-use 它,我们就回到了 UB 的第一方块:

constexpr int x = 1;

struct A {
    A() {
        printf("%p\n", &x);
    }
};

因此,鉴于我们现在有 inline 个变量,准则不应该是在 header 中将所有 namespace 范围的变量标记为 inline 以避免所有有问题吗?

constexpr inline int x = 1;

struct A {
    A() {
        printf("%p\n", &x);
    }
};

这似乎也更容易教授,因为我们可以简单地说“inline-headers 中的所有内容”(即函数和变量定义),以及 "never static in headers" .

这个推理正确吗?如果是,总是将 header 中的 constconstexpr 变量标记为 inline 是否有任何缺点?

正如您所指出的,示例一和示例三确实违反了 ODR [basic.def.odr]/12.2.1

[..] in each definition of D, corresponding names, looked up according to [basic.lookup], shall refer to an entity defined within the definition of D, or shall refer to the same entity, after overload resolution and after matching of partial template specialization, except that a name can refer to

a non-volatile const object with internal or no linkage if the object

  • is not odr-used in any definition of D, [..]

这个推理正确吗?

是的,具有外部链接的内联变量即使在 odr-used 时也保证引用相同的实体,只要所有定义都相同即可:

[dcl.inline]/6

An inline function or variable shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case ([basic.def.odr]). [..] An inline function or variable with external linkage shall have the same address in all translation units.

最后一个例子是可以的,因为它符合并且没有违反上面的粗体部分。

始终将 header 中的 const 和 constexpr 变量标记为内联是否有任何缺点?

我想不出任何一个,因为如果我们通过 TU 信守承诺,通过 TU 对具有外部链接的内联变量进行完全相同的定义,编译器可以自由选择其中任何一个来引用该变量,从技术上讲,这与只有一个 TU 并且在 header 中声明一个全局变量并带有适当的 header 守卫

是一样的