ISO/IEC 14882:2011之条款3.5——程序和连接
3.5 程序和连接
1、一个程序包含了连接在一起的一个或多个翻译单元(条款2).一个翻译单元由一个声明序列组成:
translation-unit:
declaration-seqopt
2、一个名字被称为具有连接,当这个名字可能将同一个对象、引用、函数、类型、模板、名字空间或值表示为由另一个作用域中的一个声明所引入的一个名字时:
—— 当一个名字具有外部连接时,它所表示的实体可以被来自其它翻译单元或同一个翻译单元的其它作用域的名字所引用。
—— 当一个名字具有内部连接时,它所表示的实体可以被来自同一个翻译单元的其它作用域的名字所引用。
—— 当一个名字没有连接时,它所表示的实体不能被来自其它作用域的名字所引用。
3、具有名字空间作用域(3.3.6)的一个名字具有内部连接,如果它是以下名字
—— 一个被显式声明为static的变量,函数或函数模板;或
——一个被显式声明为const或constexpr,并且既不显式地声明为extern,在之前也没有声明为具有外部连接的变量;或
——一个匿名联合体的一个数据成员
4、一个未命名的名字空间或直接或间接在一个未命名名字空间内声明的一个名字空间具有内部连接。所有其它名字空间具有外部连接。具有名字空间作用域的一个名字,并且它在上面没有给予内部连接,具有与封闭的名字空间相同的连接,如果它是以下名字
—— 一个变量;或
—— 一个函数;或
—— 一个命名的类(条款9),或在一个typedef声明中定义的一个未命名的类,而在那个声明中,该类出于连接目的具有那个typedef名(7.1.3);或
—— 一个命名的枚举(7.2),或定义在一个typedef声明中的一个未命名枚举,而在那个声明中,该枚举出于连接目的具有那个typedef名(7.1.3);或
—— 属于一个带有连接的枚举的一个枚举符;或
—— 一个模板。
5、此外,一个成员函数,静态数据成员,一个命名的类或类作用域的枚举,或定义在一个类作用域的typedef声明的枚举,诸如该类或枚举具有为连接目的的typedef名(7.1.3),具有外部连接,如果该类的名字具有外部连接。
6、定义在语句块作用域中的一个函数的名字以及由一个语句块作用域extern声明所声明的一个变量的名字具有连接。如果有带有连接的一个实体的一个可见的声明,该实体与该声明具有具有相同的名字和类型,忽略在最里面封闭的名字空间作用域的外部所声明的实体,那么该语句块作用域声明声明了同一个实体并接收先前声明的连接。如果有多个这样的匹配实体,那么程序是不良形式的。否则,如果找到没有匹配实体,那么语句块作用域实体接收外部连接。[例:
static void f(); static int i = 0; // #1 void g() { extern void f(); // 内部连接 int i; // #2 { extern void f(); // 内部连接 extern int i; // #3 外部连接 } }
在这个程序中一共有3个名字为i的对象。带有内部连接的对象由在全局作用域中的声明(行#1)所引入,带有自动存储生命周期、无连接的对象由行#2上的声明所引入,而带有静态存储声明周期并具有外部连接的对象由行#3的声明所引入。
—— 例结束]
7、当一个具有连接的实体的一个语句块作用域声明引用某些其它声明时没有被找到时,那个实体是最里面封闭的名字空间的一个成员。然而,这样的一个声明并不在其名字空间作用域中引入那个成员名。[例:
namespace X { void p() { q(); // 错误:q尚未被声明 extern void q(); // q是名字空间X的一个成员 } void middle() { q(); // 错误:q尚未被声明 } void q() { /* ... */ } // 定义了X::q } void q() { /* ... */ } // 某些其它,非相关的q
—— 例结束]
8、没有被这些规则覆盖的名字不具有连接。此外,除了提到的之外,在语句块作用域中声明的一个名字(3.3.3)不具有连接。一个类型被称为具有连接,当且仅当:
—— 它是一个命名的类或枚举类型(或具有为连接目的的一个名字(7.1.3))并且该名字具有连接;或
—— 它是一个具有连接的类的一个未命名的类或枚举成员;或
—— 它是一个类模板的一个特化(14)[注:一个类模板总是具有外部连接,并且14.3.1和14.3.2的要求确保模板实参将也具有合适的连接。];或
—— 它是一个基本类型(3.9.1);或
—— 它是一个复合类型(3.9.2)而不仅仅是一个类或枚举,排外地从具有连接的类型复合;或
—— 它是一个具有连接的类型的一个cv限定(3.9.3)版本。
一个不具有连接的类型不应该被用作为带有外部连接的一个变量或函数,除非
—— 该实体具有C连接(7.5),或
—— 该实体在一个未命名的名字空间(7.3.1)内被声明,或
—— 该实体不是使用一次定义规则的(3.2)或被定义在同一个翻译单元。
[注:换句话说,不带有连接的一个类型包含了不能在其翻译单元外命名的一个类或枚举。使用这么一个类型声明的带有外部连接的一个实体不能与在程序的另一个翻译单元中的任一其它实体相一致,从而必须被定义在翻译单元中,如果它是使用一次定义规则的。也要注意带有连接的类可以包含其类型不具有连接的成员,并且typedef名字在判定一个类型是否具有连接的过程中被忽略。 ——注结束]
[例:
template <class T> struct B { void g(T) { } void h(T); friend void i(B, T) { } }; void f() { struct A { int x; }; // 没有连接 A a = { 1 }; B<A> ba; // 声明了B<A>::g(A)以及B<A>::h(A) ba.g(a); // OK ba.h(a); // 错误:B<A>::h(A)在此翻译单元中没被定义 i(ba, a); // OK }
—— 例结束]
9、两个相同的(条款3)并且声明在不同作用域中的名字应该表示同一个变量、函数、类型、枚举符、模板或名字空间,如果
—— 两个名字都有外部连接或两个名字都有内部连接,并且同一个翻译单元中被声明;并且
—— 两个名字都引用引用同一个名字空间的成员,或同一个类的成员(不通过继承);并且
—— 当两个名字都表示函数时,函数的形参类型列表(8.3.5)是相同的;并且
—— 当两个名字表示函数模板时,其签名(14.5.6.1)是相同的。
10、在所有类型的调整之后(在所有的typedef(7.1.3)被其定义取代期间),被引用一个给定变量或函数的所有声明所指定的类型应该是相同的,除了对一个数组对象的声明可以指定数组类型,由一个主要数组边界(8.3.4)的存在或缺失不同的声明之外。在类型一致性上对此规则的违背并不需要诊断。
11、[注:对非C++声明的连接可以通过使用一个连接指定(7.5)来实现。 ——注结束]