Подтвердить что ты не робот

Что такое вложенный спецификатор имен?

Связано с этим

Я хочу знать, что именно представляет собой спецификатор вложенных имен? Я посмотрел в черновик, но я мог понять грамматику, так как я еще не занимался классами компилятора.

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;
} 
4b9b3361

Ответ 1

::S - это квалифицированный идентификатор.

В идентификаторе ::S::f, S:: используется спецификатор вложенных имен.

В неофициальных терминах 1 спецификатор вложенных имен является частью идентификатора, который

  • начинается либо в самом начале квалифицированного идентификатора, либо после первого оператора разрешения области (::), если он появляется в самом начале идентификатора и
  • заканчивается последним оператором разрешения разрешающей способности в идентификаторе с квалификацией.

Очень неформально 1 id - либо квалифицированный идентификатор, либо неквалифицированный идентификатор. Если идентификатор является идентификатором-квалифицированным, он фактически состоит из двух частей: спецификатора вложенного имени, за которым следует неквалифицированный идентификатор.

Дано:

struct  A {
    struct B {
        void F();
    };
};
  • A - это неквалифицированный идентификатор.
  • ::A является квалифицированным идентификатором, но не имеет спецификатора вложенных имен.
  • A::B - это квалифицированный идентификатор, а A:: - спецификатор вложенных имен.
  • ::A::B - это квалифицированный идентификатор, а A:: - спецификатор вложенных имен.
  • A::B::F является квалифицированным идентификатором, а B:: и A::B:: являются вложенными именами.
  • ::A::B::F является квалифицированным идентификатором, и оба B:: и A::B:: являются вложенными именами.

[1] Это довольно неточное описание. Трудно описать грамматику простым языком...

Ответ 2

Вложенный спецификатор пространства имен:

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

То есть, непустой список пространств имен и имен классов, за которыми следуют::, представляющие относительное ветвление в общем "дереве пространства имен" программы. Например, my_namespace::, my_namespace::inner_namespace::, my_namespace::my_class:: и my_class::.

Обратите особое внимание на отличие от:

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

В том, что спецификатор вложенного имени может быть не абсолютным (с префиксом :: для ссылки на глобальную область), в то время как специфицированный спецификатор имен имен может быть, но не заканчивается на ::.

В вашем примере ::S разрешается функция ::S(), а не структура (правила предвзятости для этого обсуждались здесь в Stackoverflow в вопросе, с которым вы связались в начале вашего вопроса), так что это не спецификатор вложенных имен.

Ответ 3

Хороший вопрос! Я узнал о чем-то новом исследовании и экспериментировании на нем.

Вы правы в своем комментарии, ::S(); //Is ::S a nested name specifier <-- Yes, Indeed!

Вы бы поняли, когда начинаете создавать пространства имен. Переменные могут иметь одинаковые имена в пространствах имен, а оператор :: - это то, что их отличает. Пространства имен как классы в некотором смысле, еще один слой абстракции. Я бы не захотел утомлять вас пространствами имен. В этом примере вы не можете оценить вложенный спецификатор имен... рассмотрите этот вариант:

#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;
}

Обратите внимание, что я использовал ::count, где я мог просто использовать count. ::count относится к глобальному пространству имен.

Итак, в вашем случае, поскольку S() находится в глобальном пространстве имен (т.е. он объявлен в том же файле или включенном файле или в любом фрагменте кода, где он не окутан namespace <name_of_namespace> { }, вы можете использовать new struct ::S или new struct S, в зависимости от того, что вы предпочитаете.

Я только что узнал об этом, поскольку мне было любопытно ответить на этот вопрос, поэтому, если у вас есть более конкретный и научный ответ, пожалуйста, разделите:)