根据您最初的假设:
似乎没有明确的定义
声明、声明区域、命名空间标识符的范围、
除了命名空间内的标识符——根据
标准(§3.3.6/1)。
我是从open-std.org/pdf 的标准中阅读的
3.3.6 命名空间范围 [basic.scope.namespace] 1 命名空间定义的声明区域是它的命名空间主体。申报的实体
命名空间主体被称为命名空间的成员,并且名称
由这些声明引入
命名空间被称为命名空间的成员名称。命名空间
成员名称具有命名空间范围。它的潜在范围包括
从名称的声明点(3.3.2)开始的命名空间;和
对于每个指定成员的使用指令(7.3.4)
命名空间,成员的潜在范围包括
跟随成员点的使用指令的潜在范围
的声明。 [示例:
namespace N {
int i;
int g(int a) { return a; }
int j();
void q();
}
namespace { int l=1; }
// the potential scope of l is from its point of declaration
// to the end of the translation unit
namespace N {
int g(char a) { // overloads N::g(int)
return l+a; // l is from unnamed namespace
}
int i; // error: duplicate definition
int j(); // OK: duplicate function declaration
int j() { // OK: definition of N::j()
return g(i); // calls N::g(int)
}
int q(); // error: different return type
}
——结束示例]
这使我阅读了以下部分:
3.3
3.3 范围 [basic.scope]
3.3.1 声明区域和范围 [basic.scope.declarative] 1 每个名称都在程序文本的某些部分引入,称为
声明区域,它是程序的最大部分,其中
该名称是有效的,也就是说,该名称可以用作
不合格的名称来指代同一实体。一般来说,每个
特定名称仅在某些可能不连续的范围内有效
程序文本的一部分称为其范围。确定一个范围
声明,有时方便参考潜在的
声明的范围。声明的范围与其相同
潜在范围,除非潜在范围包含另一个
同名声明。在这种情况下,潜在的范围
内部(包含)声明区域中的声明被排除在外
从外部(包含)声明的范围
声明区域。
2 [示例:在
int j = 24;
int main() {
int i = j, j;
j = 42;
}
标识符 j 被声明为名称两次(并使用了两次)。这
第一个 j 的声明区域包括整个示例。这
第一个 j 的潜在范围紧接在那个 j 之后开始,并且
延伸到程序的末尾,但其(实际)范围不包括
和 } 之间的文本。第二个声明区域
j 的声明(分号前的 j)包括所有
{ 和 } 之间的文本,但其潜在范围不包括
i 的声明。 j的第二个声明的范围是一样的
作为其潜在范围。 —end example ] 3 a 声明的名称
声明被引入声明的范围
发生,除了朋友说明符(11.3)的存在,某些
详细类型说明符 (7.1.6.3) 和使用指令的使用
(7.3.4) 改变这种一般行为。 4 给定一组声明
单个声明性区域,每个区域指定相同的
非限定名称,(4.1)——它们都应指同一实体,或
都是指函数和函数模板;或 (4.2) — 正好是一个
声明应声明一个非类名或枚举名
typedef 名称和其他声明都应引用相同的
变量或枚举数,或都指函数和函数
模板;在这种情况下,类名或枚举名是隐藏的
(3.3.10)。 [注意:命名空间名称或类模板名称必须是
在其声明区域中是唯一的(7.3.2,第 14 条)。 ——尾注]§
3.3.1 38
c ISO/IEC N4527 [注意:这些限制适用于声明性
引入名称的区域,不一定是
与声明发生的区域相同。尤其,
详细类型说明符 (7.1.6.3) 和友元声明 (11.3)
可以将(可能不可见的)名称引入封闭的
命名空间;这些限制适用于该地区。本地外部
声明(3.5)可以将名称引入声明区域
声明出现的地方并且还引入了一个(可能不是
可见)名称到封闭的命名空间中;这些限制适用于
两个地区。 —尾注] 5 [注:名称查找规则为
总结在 3.4 中。 ——尾注]
3.1
3.1 声明和定义 [basic.def] 1 声明(第 7 条)可以将一个或多个名称引入翻译单元或
重新声明先前声明引入的名称。如果是这样,则
声明指定了这些的解释和属性
名字。声明还可能具有以下效果: (1.1) — 静态
assertion (Clause 7), (1.2) — 控制模板实例化
(14.7.2)、(1.3) — 属性的使用(第 7 条)和 (1.4) — 无
(在空声明的情况下)。 § 3.1 33
c ISO/IEC N4527 2 声明是一个定义,除非它声明了一个
函数没有指定函数的主体(8.4),它包含
extern 说明符(7.1.1)或链接规范25(7.5)和
既不是初始化程序也不是函数体,它声明了一个静态数据
类定义(9.2、9.4)中的成员,它是类名
声明(9.1),它是一个不透明枚举声明(7.2),它是一个
模板参数(14.1),它是一个参数声明(8.3.5)
不是 a 的声明符的函数声明符
函数定义,或者它是一个 typedef 声明(7.1.3),一个
别名声明 (7.1.3)、使用声明 (7.3.3)、
static_assert-declaration(第 7 条),一个属性声明(Clause
7),一个空声明(第 7 条),一个使用指令(7.3.4),一个
显式实例化声明 (14.7.2),或显式
其声明不是定义的专业化(14.7.3)。 [
示例:除以下一项外,其他都是定义:
int a; // defines a
extern const int c = 1; // defines c
int f(int x) { return x+a; } // defines f and defines x
struct S { int a; int b; }; // defines S, S::a, and S::b
struct X { // defines X
int x; // defines non-static data member x
static int y; // declares static data member y
X(): x(0) { } // defines a constructor of X
};
int X::y = 1; // defines X::y
enum { up, down }; // defines up and down
namespace N { int d; } // defines N and N::d
namespace N1 = N; // defines N1
X anX; // defines anX
而这些只是声明:
extern int a; // declares a
extern const int c; // declares c
int f(int); // declares f
struct S; // declares S
typedef int Int; // declares Int
extern X anotherX; // declares anotherX
using N::d; // declares d
—结束示例] 3 [ 注意:在某些情况下,C++ 实现
隐式定义默认构造函数(12.1),复制构造函数
(12.8)、移动构造函数 (12.8)、复制赋值运算符 (12.8)、移动
赋值运算符 (12.8) 或析构函数 (12.4) 成员函数。
—尾注] [示例:给定
#include <string>
struct C {
std::string s; // std::string is the standard library class (Clause 21)
};
int main() {
C a;
C b = a;
b = a;
}
实现将隐式定义函数以使
C 的定义等价于 25) 出现在大括号内
链接规范中的声明序列不影响是否
声明是一个定义。 § 3.1 34
c ISO/IEC N4527
struct C {
std::string s;
C() : s() { }
C(const C& x): s(x.s) { }
C(C&& x): s(static_cast<std::string&&>(x.s)) { }
// : s(std::move(x.s)) { }
C& operator=(const C& x) { s = x.s; return *this; }
C& operator=(C&& x) { s = static_cast<std::string&&>(x.s); return *this; }
// { s = std::move(x.s); return *this; }
~C() { }
};
—end example ] 4 [ 注意:类名也可以隐式声明
通过详细的类型说明符(7.1.6.3)。 ——尾注] 5 一个程序是
如果任何对象的定义给该对象一个
不完整类型(3.9)。
然后你先声明:
虽然标准确实谈到了声明的内容——a
namespace-definition 是声明,不适用于
命名空间定义的情况,因为它没有声明符,也没有
初始化器——根据标准(§3.3.2/1)。
然后我读到了这个:
3.3.2 声明点 [basic.scope.pdecl] 1 名称的声明点紧跟在其完整声明符之后
(第 8 条)和它的初始化器(如果有的话)之前,除非如下所述。
[ 例子:
unsigned char x = 12;
{ unsigned char x = x; }
这里第二个 x 用它自己的(不确定的)值初始化。
—结束示例]
然后你引用这个:
名称的声明点在其完成后立即
声明符(第 8 条)和它的初始化器(如果有的话)之前,除了
如下所示...
我终于读到了:
8 声明符 [dcl.decl] 1 声明符声明一个变量,
声明中的函数或类型。初始化声明器列表
出现在声明中的是逗号分隔的序列
声明符,每个声明符都可以有一个初始化器。
init-declarator-list: init-declarator init-declarator-list ,
init-declarator init-declarator: 声明器 initializeropt 2 三个
简单声明的组成部分是属性(7.6),
说明符 (decl-specifier-seq; 7.1) 和声明符
(初始化声明符列表)。说明符表示类型、存储
被声明的实体的类或其他属性。这
声明符指定这些实体的名称和(可选)
用 * 等运算符修改说明符的类型(指针
to) 和 () (函数返回)。也可以指定初始值
在声明符中;初始化器在 8.5 和 12.6 中讨论。 3个
声明中的 init-declarator 被单独分析,就好像它是
在自己的声明中。100 4 声明符具有语法
declarator: ptr-declarator noptr-declarator parameters-and-qualifiers
trailing-return-type ptr-declarator: noptr-declarator ptr-operator
ptr-declarator noptr-declarator: declarator-id
属性说明符 seqopt noptr 声明符参数和限定符
noptr 声明符 [常量表达式选择] 属性说明符 seqopt
( ptr-declarator ) 参数和限定符:(
参数声明子句) cv-qualifier-seqopt ref-qualifieropt
exception-specificationopt 属性说明符-seqopt 100) A
带有多个声明符的声明通常等同于
相应的声明序列,每个声明都带有一个声明符。
即 T D1, D2, ... Dn;通常相当于 T D1; T D2; ...吨
DN;其中 T 是一个 decl-specifier-seq 并且每个 Di 是一个 init-declarator。
当其中一个声明符引入的名称时发生异常
隐藏由 decl-specifiers 使用的类型名称,这样当相同的
decl-specifiers 在后续声明中使用,它们没有
与 struct S ... 中的含义相同; SS,T; // 声明两个
不等价于 struct S ... 的 struct S 实例; S S;小号
T; // error 当 T 为 auto (7.1.6.4) 时发生另一个异常,对于
示例:自动 i = 1,j = 2.0; // 错误:i 和 j 的推断类型
不匹配而不是 auto i = 1; // 好的:我推断有 int 类型
自动 j = 2.0; // OK: j 推断为具有 double 类型的声明符 190
c ISO/IEC N4527 尾随返回类型:
-> 尾随类型说明符序列抽象声明器选择 ptr 运算符:
* 属性说明符 seqopt cv 限定符 seqopt & 属性说明符 seqopt && 属性说明符 seqopt
嵌套名称说明符 * 属性说明符 seqopt cv 限定符 seqopt
cv-qualifier-seq:cv-qualifier cv-qualifier-seqopt cv-qualifier:const
volatile ref-qualifier: & && declarator-id: ...opt id-expression 5
尾随返回类型中的可选属性说明符序列
到指定的返回类型。尾随返回类型中的类型 ID
包括最长可能的抽象声明符序列。 [
注意:这解决了数组和函数的模糊绑定
声明者。 [ 示例:自动 f()->int(*)[4]; // 函数返回一个
指向 int 数组 [4] 的指针 // 不是返回数组 [4] 的函数
指向 int 的指针——结束示例]——结束注释]
你终于问这个了:
那么,如何确定命名空间标识符的那些?
您是否继续阅读本节?
7.3 命名空间 [basic.namespace] 1 命名空间是一个可选命名的声明区域。命名空间的名称可用于访问
在该命名空间中声明的实体;也就是说,成员
命名空间。与其他声明性区域不同,a 的定义
命名空间可以拆分为一个或多个翻译的多个部分
单位。 2 翻译单元的最外层声明区域是
命名空间;见 3.3.6。
7.3.1 命名空间定义 [namespace.def] 1 命名空间定义的语法是 namespace-name: identifier namespace-alias
命名空间定义:命名命名空间定义
未命名命名空间定义嵌套命名空间定义
命名命名空间定义:inlineopt 命名空间
属性说明符 seqopt 标识符 { namespace-body }
未命名命名空间定义:inlineopt 命名空间
属性说明符序列选择{命名空间主体}
嵌套命名空间定义:命名空间封闭命名空间说明符
:: 标识符 { namespace-body } 封闭命名空间说明符:
标识符封闭命名空间说明符 :: 标识符 § 7.3.1 168
c ISO/IEC N4527 namespace-body: declaration-seqopt 2 Every
命名空间定义应出现在全局范围内或
命名空间范围(3.3.6)。 3 在命名命名空间定义中,
标识符是命名空间的名称。如果是标识符,当
查找(3.4.1),指的是命名空间名称(但不是
namespace-alias) 在声明区域中引入,其中
named-namespace-definition 出现,namespace-definition 扩展
先前声明的命名空间。否则,标识符为
作为命名空间名称引入声明区域,其中
出现命名命名空间定义。 4 因为一个
namespace-definition 在其 namespace-body 中包含声明和一个
namespace-definition 本身就是一个声明,它遵循
命名空间定义可以嵌套。 [ 例子:
namespace Outer {
int i;
namespace Inner {
void f() { i++; } // Outer::i
int i;
void g() { i++; } // Inner::i
}
}
—结束示例]
5 声明的封闭命名空间是
声明在词汇上出现,除了重新声明
其原始名称空间之外的名称空间成员(例如,定义
如 7.3.1.2 所述)。这样的重新声明具有相同的封闭
命名空间作为原始声明。 [ 例子:
namespace Q {
namespace V {
void f(); // enclosing namespaces are the global namespace, Q, and Q::V
class C { void m(); };
}
void V::f() { // enclosing namespaces are the global namespace, Q, and Q::V
extern void h(); // ... so this declares Q::V::h
}
void V::C::m() { // enclosing namespaces are the global namespace, Q, and Q::V
}
}
—结束示例] 6 如果可选的初始内联关键字出现在
特定命名空间的命名空间定义,该命名空间是
声明为内联命名空间。 inline 关键字可用于
一个命名空间定义,仅在命名空间是
先前用于最初声明的命名空间定义
该命名空间的命名空间名称。 7 可选
命名命名空间定义中的属性说明符序列属于
被定义或扩展的命名空间。 8 个内联成员
命名空间可以在大多数方面使用,就好像它们是
封闭的命名空间。具体来说,内联命名空间及其
封闭的命名空间都被添加到关联的命名空间集中
只要其中一个是,就在参数相关查找(3.4.2)中使用,并且
隐式命名内联命名空间的 using 指令 (7.3.4)
插入到封闭的命名空间中,就像未命名的命名空间一样
(7.3.1.1)。此外,内联命名空间的每个成员都可以
随后被部分专业化(14.5.5),明确
实例化 (14.7.2),或显式特化 (14.7.3),就好像它
是封闭命名空间的成员。最后查了个名字
通过 § 7.3.1 169
在封闭的命名空间中
c ISO/IEC N4527 明确资格 (3.4.3.2) 将包括成员
由 using 指令引入的内联命名空间,即使
在封闭的命名空间中有该名称的声明。 9
这些属性是可传递的:如果命名空间 N 包含内联
命名空间 M,它又包含一个内联命名空间 O,然后
O 的成员可以像 M 或 N 的成员一样使用。
N 的内联命名空间集是所有内联的传递闭包
N 中的命名空间。O 的封闭命名空间集是
由最里面的非内联命名空间组成的命名空间
一个内联命名空间 O,以及任何介入的内联
命名空间。 10 嵌套命名空间定义
封闭命名空间说明符 E、标识符 I 和命名空间主体 B 是
相当于命名空间 E { 命名空间 I { B } }
[ 例子:
namespace A::B::C {
int i;
}
上面的效果与:
namespace A {
namespace B {
namespace C {
int i;
}
}
}
——结束示例]
我认为可以从定义 7.3 - 1 & 2 和 7.3.1 - 2,3 & 4 中找到回答您问题的重要性线。前提是您正在使用命名的命名空间并且您已经了解范围、翻译单元,声明,定义和声明空间。在声明器部分中没有提到命名空间的声明器,因为它在命名空间部分下的声明部分中列出,因为命名命名空间或其定义是它的声明,因此标识符是命名空间本身的名称或其定义 - 声明。