标题中的`const`和`constexpr`变量应该是'inline`以防止ODR违规吗?

Aco*_*orn 15 c++ language-lawyer c++17

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

static int x = 0;

struct A {
    A() {
        ++x;
        printf("%d\n", x);
    }
};
Run Code Online (Sandbox Code Playgroud)

正如这个问题所解释的那样,这是ODR违规,因此也就是UB.

现在,如果我们的函数引用非对象并且我们不在该函数中使用它(加上其他条款),则不存在ODR违规,因此这在头文件中仍然可以正常工作:inlinevolatile const

constexpr int x = 1;

struct A {
    A() {
        printf("%d\n", x);
    }
};
Run Code Online (Sandbox Code Playgroud)

但如果我们确实碰巧使用它,我们又回到UB的第一个方面:

constexpr int x = 1;

struct A {
    A() {
        printf("%p\n", &x);
    }
};
Run Code Online (Sandbox Code Playgroud)

因此,鉴于我们现在有inline变量,指南是否应该在标题中标记所有namespace变量inline以避免所有问题?

constexpr inline int x = 1;

struct A {
    A() {
        printf("%p\n", &x);
    }
};
Run Code Online (Sandbox Code Playgroud)

这似乎也更容易教,因为我们可以简单地说" inline标题中的所有内容"(即函数和变量定义),以及"从不static在标题中".

这个推理是否正确?如果是的话,总是在标题中标记constconstexpr变量是否有任何缺点inline

Jan*_*ans 7

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

[...]在D的每个定义中,相应的名称,根据[basic.lookup]查找,应指在D的定义内定义的实体,或者在重载解析后和匹配后应引用同一实体.部分模板特化,除了名称可以引用

一个非易失性const对象,如果是对象,则内部或没有链接

  • 在D的任何定义中都没有用过,[..]

这个推理是否正确?

是的,具有外部链接的内联变量保证引用同一个实体,即使它们使用的时间长,所有定义都相同:

[dcl.inline]/6

内联函数或变量应在每个使用过的翻译单元中定义,并且在每种情况下都应具有完全相同的定义([basic.def.odr]).[..]具有外部链接的内联函数或变量在所有翻译单元中应具有相同的地址.

最后一个例子是可以的,因为它符合并且不违反上述的粗体部分.

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

我想不出任何一个,因为如果我们保证通过TU的外部链接具有完全相同的内联变量定义,编译器可以自由选择它们中的任何一个来引用变量,这将是相同的从技术上讲,只有一个TU,并在标题中声明了一个带有适当标题保护的全局变量