C++ C++;标准:命名空间范围的constexpr变量是否具有内部链接?
假设我们有一个包含以下内容的标题C++ C++;标准:命名空间范围的constexpr变量是否具有内部链接?,c++,c++11,language-lawyer,c++17,linkage,C++,C++11,Language Lawyer,C++17,Linkage,假设我们有一个包含以下内容的标题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之间是否有所不同 标准草案中说 如果名称空间范围为[…]的名称是非易失性常量限定类型的非内联变量,且该变量
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之间是否有所不同
标准草案中说
如果名称空间范围为[…]的名称是非易失性常量限定类型的非内联变量,且该变量既没有显式声明为extern,也没有先前声明为具有外部链接[…],则该名称具有内部链接
但我不知道constexpr
是否算作“const-qualified”。标准中有这样的规定吗
假设保证有内部链接,ODR在这种情况下似乎不会有问题,对吗?(与中所述相反。)是的,对象声明上的
constexpr
表示对象是const
。看见是的,这意味着在您的示例中,kSomeString
具有内部链接
我们在这里讨论的ODR违规种类不是kSomeString
本身的定义,而是试图使用它的其他定义。而问题恰恰是因为内部联系。考虑:
void f(const std::string_view &);
inline void g() {
f(foo::kSomeString);
}
如果包含在多个翻译单元中,这就是ODR冲突,主要是因为每个翻译单元中的
g
的定义引用了不同的对象。您对kSomeString
的使用完全有效
第一件事优先;正如T.C.所解释的,您的对象是const限定的。更重要的是,它有一个constexpr构造函数。因此,如果在头文件中定义的函数中使用它,则本标准中的以下例外情况适用(第3.2章):
具有的内联函数可以有多个定义
外部联动装置(7.1.2),非静态功能模板(14.5.6),(…)
在程序中,只要每个定义以不同的形式出现
翻译单位,并提供满足以下要求的定义
要求。给定一个以上定义的名为D的实体
翻译单位,那么
- D的每个定义应包含相同的令牌序列;及
- 在D的每个定义中,根据3.4查找的相应名称应指D定义中定义的实体, 或应指过载解决后的同一实体(13.3) 在匹配部分模板专门化(14.8.3)后, 除了名称可以引用具有内部或无内部属性的常量对象之外 链接,如果对象在所有的定义中具有相同的文字类型 D、 并且该对象用常量表达式(5.19)初始化, 使用对象的值(而不是地址),并且 对象在D的所有定义中具有相同的值李>
- (……)
是的,声明中的
constepr
意味着C++11中的const
。在C++14及更高版本中,它仅在变量上暗示const
,而不是在成员函数上。谢谢!你知道标准的哪一部分是这样写的吗?谢谢!您的ODR问题示例很有意义-g
在每个翻译单元中都不相同。可能存在不涉及内联函数的问题吗?@jacobsa:使用非类型参数的模板是另一个明显的例子。@t.C.,恐怕我不太同意你的看法,请看我的答案。“使用的是对象的值(而不是地址)”。绑定引用使用它的地址。@T.C.你是对的,但我没有错:)。我不鼓励接受它的地址。我同意您的特殊使用是一个陷阱,但我想指出的是,在共享定义中使用这样的对象通常是正确的。