Что такое вложенный спецификатор имен?
Связано с этим
Я хочу знать, что именно представляет собой спецификатор вложенных имен? Я посмотрел в черновик, но я мог понять грамматику, так как я еще не занимался классами компилятора.
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;
}
Ответы
Ответ 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
, в зависимости от того, что вы предпочитаете.
Я только что узнал об этом, поскольку мне было любопытно ответить на этот вопрос, поэтому, если у вас есть более конкретный и научный ответ, пожалуйста, разделите:)