What is a nested name specifier?

2019-01-11 12:50发布

Related to this

I want to know what exactly is a nested name specifier? I looked up in the draft but I could understand the grammar as I haven't taken any Compiler Design classes yet.

void S(){}

struct S{
   S(){cout << 1;}
   void f(){}
   static const int x = 0;
}; 

int main(){ 
   struct S *p = new struct ::S;  
   p->::S::f();

   S::x;  

   ::S(); // Is ::S a nested name specifier?
   delete p;
} 

标签: c++ names
3条回答
Luminary・发光体
2楼-- · 2019-01-11 13:12

Good question! I learnt something new researching and experimenting on it.

You are right in your comment, ::S(); //Is ::S a nested name specifier <-- Yes, Indeed!

You would come to appreciate it when you start creating namespaces. Variables can have the same names across namespaces and the :: operator is what distinguishes them. Namespaces are like classes in a sense, another layer of abstraction. I wouldn't want to bore you with namespaces. You may not appreciate the nested name specifier in this example...consider this one:

#include <iostream>
using namespace std;

int count(0);                   // Used for iteration

class outer {
public:
    static int count;           // counts the number of outer classes
    class inner {
    public:
        static int count;       // counts the number of inner classes
    };
};

int outer::count(42);            // assume there are 42 outer classes
int outer::inner::count(32768);  // assume there are 2^15 inner classes
                                 // getting the hang of it?

int main() {
    // how do we access these numbers?
    //
    // using "count = ?" is quite ambiguous since we don't explicitly know which
    // count we are referring to.
    //
    // Nested name specifiers help us out here

    cout << ::count << endl;        // The iterator value
    cout << outer::count << endl;           // the number of outer classes instantiated
    cout << outer::inner::count << endl;    // the number of inner classes instantiated
    return 0;
}

Notice that I used ::count where I could have simply used count. ::count refers to the global namespace.

So in your case, since S() is in the global namespace (i.e. it's declared in the same file or an included file or any piece of code where it's not enveloped by namespace <name_of_namespace> { }, you could use new struct ::S or new struct S; whichever you prefer.

I just learnt this as I was curious to answer this question so if you have a more specific and learned answer, please do share :)

查看更多
劳资没心,怎么记你
3楼-- · 2019-01-11 13:13

A nested namespace specifier is:

nested-name-specifier :
    class-or-namespace-name::nested-name-specifier(optional)

That is, a non-empty list of namespaces and classnames, each followed by ::, representing a relative branching in the overall "namespace tree" of the program. For example, my_namespace::, my_namespace::inner_namespace::, my_namespace::my_class::, and my_class::.

Note specifically the difference from:

qualified-namespace-specifier :
    ::(optional) nested-name-specifier(optional) class-or-namespace-name

In that a nested-name-specifier may not be absolute (prefixed with :: to refer to the global scope), while a qualified-namespace-specifier can be, but doesn't end with ::.

In your example, ::S resolves to the function ::S(), and not the struct (precendence rules for that were discussed here on Stackoverflow in the question you linked to at the start of your question), so it is not a nested name specifier.

查看更多
趁早两清
4楼-- · 2019-01-11 13:30

::S is a qualified-id.

In the qualified-id ::S::f, S:: is a nested-name-specifier.

In informal terms1, a nested-name-specifier is the part of the id that

  • begins either at the very beginning of a qualified-id or after the initial scope resolution operator (::) if one appears at the very beginning of the id and
  • ends with the last scope resolution operator in the qualified-id.

Very informally1, an id is either a qualified-id or an unqualified-id. If the id is a qualified-id, it is actually composed of two parts: a nested-name specifier followed by an unqualified-id.

Given:

struct  A {
    struct B {
        void F();
    };
};
  • A is an unqualified-id.
  • ::A is a qualified-id but has no nested-name-specifier.
  • A::B is a qualified-id and A:: is a nested-name-specifier.
  • ::A::B is a qualified-id and A:: is a nested-name-specifier.
  • A::B::F is a qualified-id and both B:: and A::B:: are nested-name-specifiers.
  • ::A::B::F is a qualified-id and both B:: and A::B:: are nested-name-specifiers.

[1] This is quite an inexact description. It's hard to describe a grammar in plain English...

查看更多
登录 后发表回答