rule for :: operator in c++
c++, language-lawyer
Solution
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`:
- we use 5.1.1p8, which requires evaluation of `A::B::C::D`;
- we use 3.4.3p1, which requires evaluation of `A::B::C`;
- we use 3.4.3p1, which requires evaluation of `A::B`;
- we use 3.4.3p1, which requires evaluation of `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.
Problem
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?