我对以下变量的联系有一些疑问。通过 C++03 7.1.1/7 的示例和编译器(Comeau、Clang 和 GCC)的实验,我得出以下链接类型:
首先
static
,然后extern
static int a; // (a) extern int a; // (b) valid, 'a' still internal
根据第 3.5 节,我很清楚:(a)意味着内部联系。并且(b)也暗示了内部链接,因为名称“a”被声明为静态(由(a))。
首先
extern
,然后static
extern int b; // (c) static int b; // (d) invalid!
首先,(c)意味着外部联系。但是(d)意味着内部链接,因为名称“b”被(d)声明为静态。根据 7.1.1/7,这是无效的,因为隐含的链接不一致。
首先
const
,然后extern
const double pi1 = 3.14; // (e) extern const double pi1; // (f) valid and 'pi1' is internal
首先,(e) 暗示了内部链接,因为它是 const 的,既没有显式声明 extern,也没有先前暗示的外部链接。并且 (f) 应该暗示外部链接并且是一个错误,因为它显式声明了名称 extern,但编译器将其保留在内部!为什么这样? 那是我的问题。
首先
extern
,然后const
extern const double pi2; // (g) const double pi2 = 3.14; // (h) valid and 'pi2' is external
现在,(g) 暗示了外部链接,因为我们明确声明了 extern。并且 (h) 也意味着外部链接,因为 (g) 显式声明了 extern。
我已经通过以下模板通过实验发现了 3 和 4 的链接(第二个参数需要具有外部链接)
template<typename T, T&> struct ensure { };
ensure<const double, pi1> e1; // failed
ensure<const double, pi2> e2; // succeeded
总结:与查尔斯·贝利的讨论结果非常有成果,并表明有两种可能的解释3.5/3
,其中重要的要点是
具有命名空间范围 (3.3.5) 的名称如果是
- 显式声明为 const 且既未显式声明 extern 也未先前声明具有外部链接的对象或引用;
如果我们看点(f)
,那么两种解释会得出不同的结论,如下图所示
第一个解释说明
pi1
是声明const
的,但也是声明extern
的。因此,该变量具有外部联系。第二种解释将“已声明”的两次出现解释为指代相同的声明。这样,它意味着它是声明
const
的,而不是extern const
声明的。我们注意到(e)
是声明的const
而不是声明的extern const
,因此我们给出了pi1
内部链接。
现在什么解释是正确的?我无法从该措辞中确定,但编译器似乎以第二种方式解释了这一点。特别是,如果我们采用第一种解释,那么最后引用的部分3.5/3
将是多余的,因为不会有一个有效的场景,其中一个名称将被声明const
并且之前声明了外部链接但没有显式的extern
.