Reputation:
I think that the ::
operator can be unary in the case of accessing the global scope. In all other cases ::
is treated as a binary operator, and the evaluation rule for the ::
operator in the case of N1::N2::N3::n
is equivalent to the following:
((N1::N2)::N3)::n // Error: ::n has not been declared
But that line doesn't compile. It is very curious. There is not any information in the standard about the evaluation of nested-name-specifier
. It would be natural if the evaluation of nested-name-specified
is equivalent to qualified/unqualified-id
, but it does not say this anywhere in the standard. So can we assume that evaluation of a nested-name-specifier
is implementation-dependent?
Upvotes: 11
Views: 539
Reputation: 23031
In [expr.prim.general]
(5.1.1/8-9) the parsing rules of ::
are listed. It requires that ::
is followed by the name of a namespace/class or the name of a member of a namespace/class. (
and )
are not allowed.
More specifically in [over.oper]
(13.5/1) the standard defines operator-function-id
and operator
as one of new
, delete
, +
, -
, !
, =
, ˆ=
, &=
, <=
, >=
, ()
, []
, new[]
, *
, <
, |=
, &&
, delete[]
, /
, >
, <<
, ||
, %
, +=
, >>
, ++
, ˆ
, -=
, >>=
, --
, &
, *=
, <<=
, ,
, |
, /=
, ==
, ->*
, ∼
, %=
, !=
, ->
.
.
, .*
, ::
, ?:
are named as an exception in clause 9 to not act as ordinary unary or binary operators.
Upvotes: 9
Reputation: 157414
The scope resolution operator ::
is right-associative because the recursive grammar of the nested-name-specifier production is right-associative:
nested-name-specifier:
::[opt] type-name ::
::[opt] namespace-name ::
decltype-specifier ::
nested-name-specifier identifier ::
nested-name-specifier template[opt] simple-template-id ::
The appropriate rule for recursively evaluating a nested-name-specifier is then 3.4.3 [basic.lookup.qual]:
1 - The name of a class or namespace member or enumerator can be referred to after the
::
scope resolution operator (5.1) applied to a nested-name-specifier that denotes its class, namespace, or enumeration. [...]
Importantly, unlike 5.1, which only discusses lookup of qualified-ids (in 5.1.1p8), 3.4.3p1 is unrestricted and so can be used to lookup nested-name-specifiers recursively.
That is, in:
namespace A {
namespace B {
struct C {
struct D {
static int i;
};
};
}
}
A::B::C::D::i;
A::B::C::D::i
is parsed as a qualified-id containing recursively the nested-name-specifiers A::B::C::D::
, A::B::C::
, A::B::
, and A::
. Now, to evaluate A::B::C::D::i
:
A::B::C::D
;A::B::C
;A::B
;A
.Now we have to find a sense in which A
"denotes" a "class, namespace or enumeration". In the absence of anything more specific, section 3 refers us to 3.4:
1 - The name lookup rules apply uniformly to all names (including typedef-names (7.1.3), namespace-names (7.3), and class-names (9.1)) wherever the grammar allows such names in the context discussed by a particular rule. [...]
The lookup of A
now proceeds according to the rules of 3.4.1 [basic.lookup.unqual] as applied to the particular context. Since we are in global scope, 3.4.1p4 applies and we search global scope for name A
. We find the namespace A
, and evaluation of A::B::C::D::i
proceeds accordingly.
That is, the leftmost (innermost) name in a nested-name-specifier is looked up as an unqualified name; successive names are looked up as qualified names on their inner nested-name-specifier.
Upvotes: 8
Reputation: 179991
There's nothing implementation dependent. You are incorrectly assuming it's an operator, though. It's not. Therefore, it's neither a unary nor a binary operator, and it does not form expressions. And since it doesn't form expressions, there's no evaluation of those expressions.
Upvotes: 1