想象一下,我们有一个包含以下内容的标题foo.h
:
#ifndef FOO_H_
#define FOO_H_
namespace foo {
constexpr std::string_view kSomeString = "blah";
}
#endif // FOO_H_
foo::kSomeString
是否保证在任何包含foo.h
的翻译单元中都有内部链接?这在C ++ 11和C ++ 17之间有所不同吗?
在草案标准[basic.link]/3说
具有命名空间作用域的名称具有内部链接,如果它是非易失性const限定类型的非内联变量的名称,该变量既未显式声明为extern,也未声明为具有外部链接[...]
但我不知道constexpr
是否算作“const-qualified”。标准是否在某处说出来?
假设这保证具有内部链接,看起来ODR对此用法没有问题,对吧? (与this answer所说的相反。)
是的,constexpr
对象声明意味着对象是const
。见[dcl.constexpr]/9。是的,这意味着你的例子中的kSomeString
有内部联系。
我们在这里讨论的ODR违规物种不是kSomeString
本身的定义,而是其他试图使用它的定义。正是由于内部联系,存在一个问题。考虑:
void f(const std::string_view &);
inline void g() {
f(foo::kSomeString);
}
如果包含在多个翻译单元中,这是ODR违规,主要是因为每个翻译单元中g
的定义引用了不同的对象。
您对kSomeString
的使用是完全有效的。
首先要做的事情;你的对象是const限定的,如T.C.解释。还有literal type,因为它有一个constexpr构造函数。因此,如果在头文件中定义的函数中使用它,则标准中的以下异常适用(第3.2章):
内联函数可以有多个定义,外部链接(7.1.2),非静态函数模板(14.5.6),(...)在程序中,每个定义出现在不同的翻译单元中,并提供这些定义满足以下要求。鉴于这样一个名为D的实体在多个翻译单元中定义,那么
- D的每个定义应由相同的令牌序列组成;和
- 在D的每个定义中,根据3.4查找的相应名称,应指在D的定义中定义的实体,或者在重载决议(13.3)之后和部分模板专业化匹配之后应引用同一实体(14.8) .3),除了如果对象在D的所有定义中具有相同的文字类型,并且该对象用常量表达式(5.19)初始化,并且值(但不使用对象的地址),并且对象在D的所有定义中具有相同的值;
- (…)