我有一个关于constexpr定义一个文字类型的静态数据成员的问题,该成员在类定义中声明为const(并且未指定inline或constexpr):
// S.h
struct S
{
static int const i; // not specified inline or constexpr
};
// S.cpp
#include "S.h"
constexpr int const S::i = 42; // definition, not declaration
// main.cpp
#include "S.h"
int main()
{
return S::i;
}
Clang / gcc在C ++ 11/14模式下返回42,但在C ++ 17模式下报告错误(对S :: i的未定义引用)。如果我注释掉constexpr,它们也会在C ++ 17模式下返回42。
S :: i具有外部链接,因为S具有外部链接。 S :: i未被声明为constexpr,因此(如果我没有记错)C ++ 17 10.1.5 p1不适用:
使用constexpr声明的函数或静态数据成员 说明符隐式地是内联函数或变量
我理解这句话好像意味着(大胆的理解): 使用类定义中的constexpr说明符声明的静态数据成员隐式地是内联变量
因此S :: i不是内联变量。 然而,S :: i的定义似乎在C ++ 17模式中具有内部链接,就好像constexpr意味着内联。它是否正确?如果是这样,标准中的证据在哪里?
或者我误解了10.1.5 p1,这真的意味着(大胆的误解): 使用类定义中的constexpr说明符和名称空间范围中的定义声明的静态数据成员是隐式的内联变量吗?
答案 0 :(得分:1)
然而,S :: i的定义似乎在C ++ 17中具有内部联系 模式好像constexpr意味着内联。它是否正确?如果是这样的话 标准中的证据?
是的,这是正确的。 cppreference:
内联说明符,用于变量的decl-specifier-seq 具有静态存储持续时间(静态类成员或命名空间范围) 变量),将变量声明为内联变量。
声明constexpr的静态成员变量(但不是命名空间范围变量)隐式地是内联变量。 (自C ++ 17起)
答案 1 :(得分:0)
如果内联声明了具有外部链接的函数或变量 一个翻译单元,应在所有翻译中内联声明 出现的单位;无需诊断。
正如您所指出的那样, if 我们可以证明constexpr
隐式暗示inline
,它会解释您示例中未定义的引用错误。
[dcl.constexpr]/1州[强调我的]:
constexpr说明符应仅应用于的定义 变量或变量模板或函数或的声明 功能模板。
以及:
使用constexpr说明符声明的函数或静态数据成员 隐含地是内联函数或变量([dcl.inline])。
[basic.def]/1州[强调我的]:
声明可以在翻译单元中引入一个或多个名称 之前声明引入的或重新声明的名称。
以及(/ 2):
声明是一个定义,除非:
[...不适用于
constexpr int const S::i = 42;
]
这里的本质是定义是声明(完全定义声明引入的实体),因此constexpr int const S::i = 42;
也是(除了作为定义)a(重新定义) )声明,在这种情况下[dcl.constexpr] / 1适用,并且S::i
在{dcl.inline] / 6的S.cpp
翻译单元内嵌在所有其他翻译单元中它出现在哪里。相反,通过[dcl.constexpr] / 1,constexpr
说明符,例如特别是在静态数据成员的上下文中,只能出现在定义的声明中。
在后者的上下文中有些相关的是,带有初始化的constexpr
静态数据成员声明也是从C ++ 17开始的一个定义,允许constexpr
的规范仅应用于变量定义(即,永远不应用于非初始化声明)。请参阅[depr.static_constexpr]/1。