我认为在访问全局作用域的情况下,::
操作符可以是一元的。在所有其他情况下,将::
视为二元算子,N1::N2::N3::n
情况下::
算子的求值规则等于以下规则:
((N1::N2)::N3)::n // Error: ::n has not been declared
但是这一行不能编译。这很奇怪。标准中没有任何关于nested-name-specifier
评价的信息。如果nested-name-specified
的求值等于qualified/unqualified-id
, ,这是很自然的,但在标准中没有任何地方这样说。那么我们可以假设nested-name-specifier
的求值是依赖于实现的吗?
[expr.prim.general]
(5.1.1/8-9)中列出了::
的解析规则。它要求::
后跟名称空间/类的名称或名称空间/类的成员的名称。不允许使用(
和)
。
更确切地说在[over.oper]
(13.5/1)标准定义了operator-function-id
和operator
new
之一,delete
, +
, -
, !
, =
, ˆ=
, &=
, <=
, >=
, ()
, []
, new[]
, *
, <
, |=
, &&
, delete[]
, /
, >
, <<
, ||
, %
, +=
, >>
, ++
, ˆ
, -=
, >>=
, --
, &
, *=
, <<=
, ,
, |
, /=
, ==
, ->*
, ∼
, %=
, !=
->
。
.
, .*
, ::
, ?:
在第9条中被命名为不作为普通一元或二元操作符的例外。
范围解析运算符::
是右结合的,因为嵌套名称说明符的递归语法是右结合的:
nested-name-specifier:
::[opt] type-name ::
::[opt] namespace-name ::
decltype-specifier ::
nested-name-specifier identifier ::
nested-name-specifier template[opt] simple-template-id ::
递归计算嵌套名称说明符的适当规则是3.4.3 [basic.lookup.qual]:
重要的是,与只讨论查找限定ids(在5.1.1p8中)的5.1不同,3.4.3p1是不受限制的,因此可用于递归查找嵌套名称说明符s。1 -类或命名空间成员或枚举数的名称可以在
::
作用域解析运算符(5.1)应用于表示其类、命名空间或枚举的嵌套名称说明符之后引用。[…]
即:
namespace A {
namespace B {
struct C {
struct D {
static int i;
};
};
}
}
A::B::C::D::i;
A::B::C::D::i
被解析为限定id,递归地包含嵌套名称说明符 A::B::C::D::
、A::B::C::
、A::B::
和A::
。现在,计算A::B::C::D::i
:
- 我们使用5.1.1p8,需要评估
A::B::C::D
; - 我们使用3.4.3p1,需要评估
A::B::C
; - 我们使用3.4.3p1,需要评估
A::B
; - 我们使用3.4.3p1,这需要评估
A
。
现在我们必须找到A
"表示"一个"类、名称空间或枚举"的意义。由于没有更具体的内容,第3节让我们参考3.4:
1 -名称查找规则统一应用于所有名称(包括typedef-names (7.1.3), namspace -names(7.3)和class-names(9.1)),只要语法允许在特定规则讨论的上下文中使用这些名称。[…]
A
的查找现在根据3.4.1 [basic.lookup]的规则进行。unequal]应用于特定上下文。因为我们在全局作用域中,所以应用3.4.1p4,我们在全局作用域中搜索名称A
。我们找到命名空间A
,并对A::B::C::D::i
求值。
也就是说,嵌套名称说明符中的最左边的(最里面的)名称将作为非限定名称查找;连续的名称在其内部嵌套名称说明符上作为限定名称查找。
没有任何实现依赖。但是,您错误地假设它是一个运算符。它不是。因此,它既不是一元操作符,也不是二元操作符,而且它不形成表达式。因为它不形成表达式,所以没有对这些表达式求值。