Должно ли имя вложенного класса рассматриваться как текущий экземпляр, когда оно используется во вложенном шаблоне класса

#c #templates #language-lawyer

#c #шаблоны #язык-юрист

Вопрос:

Согласно правилу:
temp.res #3

Когда определенный идентификатор предназначен для ссылки на тип, который не является членом текущего экземпляра ([temp.dep.type] ), а его спецификатор вложенного имени ссылается на зависимый тип, он должен иметь префикс ключевого слова typename, образуя спецификатор typename . Если квалифицированный идентификатор в спецификаторе typename не обозначает тип или шаблон класса, программа неправильно сформирована.

Это означает, что когда член текущего экземпляра используется в качестве спецификатора типа, ему не обязательно указывать префикс ключевого typename слова .

Пожалуйста, рассмотрите следующий код:

 #include <iostream>
template<class T>
struct A{
    struct B{
        struct C{
           A::B* p; //#5
        };
      B::C c;  //#3
      A::B::C d; //#4
    };
    A::B a;  //#1
    /*B::C b;*/  //#2
};
int main(){

}
 

Определение для текущего экземпляра:
temp.dep.type#1

Имя ссылается на текущий экземпляр, если оно

  1. в определении шаблона класса, вложенного класса шаблона класса, члена шаблона класса или члена вложенного класса шаблона класса, введенное имя класса шаблона класса или вложенного класса,
  2. в определении шаблона основного класса или члена шаблона основного класса имя шаблона класса, за которым следует список аргументов шаблона основного шаблона (как описано ниже), заключенный в <> (или эквивалентный шаблон псевдоним специализация),
  3. в определении вложенного класса шаблона класса имя вложенного класса, на которое ссылаются как на член текущего экземпляра, или

Объявление at #1 правильно сформировано из-за первого маркера current instantiation . то есть, at #1 , имя A — это имя current instantiation , аналогичное for #3 .

#4 правильно сформирован, поскольку он подчиняется третьему маркеру current instantiation , следовательно , для A::B , где B — имя текущего экземпляра.

Однако я не могу понять, почему #2 оно неправильно сформировано, другими словами, для этого требуется ключевое typename слово, согласно первому маркеру, разве имя вложенного класса не должно рассматриваться как имя текущего экземпляра?

Честно говоря, я не знаю, как понимать первую пулю. По крайней мере, я чувствую, что это предложение расплывчато. Означает ли это, что все эти injected-class-name s (имя основного класса или имя вложенного класса) рассматриваются как имя текущего экземпляра до тех пор, пока в одном из определений, перечисленных в предложении? #2 кажется, не поддерживает эту интерпретацию.

Из примера я могу сделать вывод, что enclosing class name in вложенный класс можно рассматривать как имя текущего экземпляра, но не наоборот. Если понять предложение таким образом, можно понять, почему код at #5 правильно сформирован.

Итак, как правильно прочитать первый маркер? Согласны ли вы, что предложение является расплывчатым?

Комментарии:

1. type это не ключевое слово. Вы имеете в виду typename ?

2. @largest_prime_is_463035818 да, опечатка

Ответ №1:

Должно ли имя вложенного класса рассматриваться как текущий экземпляр, когда оно используется во вложенном шаблоне класса?

Нет.

Однако, как и во многих других отрывках стандарта, параграф [temp.dep.type]/1.1 действительно полон:

Имя ссылается на текущий экземпляр, если оно

  • (1.1) в определении шаблона класса, вложенного класса шаблона класса, члена шаблона класса или члена вложенного класса шаблона класса, введенное имя класса шаблона класса или вложенного класса, […]

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

Имя ссылается на текущий экземпляр, если оно,

  • в определении шаблона класса введенное имя класса шаблона класса [«или вложенный класс» в этом случае не применяется]
  • в определении вложенного класса шаблона класса введенное имя класса шаблона класса или [вложенного] класса
  • в определении члена шаблона класса введенное имя класса шаблона класса [«или вложенный класс» в этом случае не применяется]
  • в определении члена вложенного класса шаблона класса введенное имя класса шаблона класса или [вложенного] класса

где я подчеркнул связь «если оно находится в определении X (из Y), введенное имя класса X (или [the] Y. Особо следует отметить, что, когда определение относится к шаблону класса (когда X является шаблоном класса), в последней части нет «вложенного класса», на который можно ссылаться при описании «введенного имени класса«.

И наоборот, невозможно интерпретировать [temp.dep.type]/1.1 как

» в определении шаблона класса введенное имя класса шаблона класса или любого вложенного класса шаблона класса «

Таким образом, в вашем примере #2 мы находимся в определении шаблона класса (а именно A ), что означает только имя самого шаблона класса, а именно A , относится к текущему экземпляру.


Согласны ли вы, что предложение является расплывчатым?

Учитывая вышесказанное, я бы не сказал, что оно расплывчатое (поскольку это подразумевало бы некоторую двусмысленность, которую я не вижу), но, возможно, излишне сложное. Возможно, было бы понятнее, если бы [temp.dep.type]/1.1 был разделен на два отдельных абзаца:

Имя ссылается на текущий экземпляр, если оно

  • (1.1a) в определении шаблона класса или члена шаблона класса введенное имя класса шаблона класса,
  • (1.1b) в определении вложенного класса шаблона класса или члена вложенного класса шаблона класса введенное имя класса шаблона класса или вложенного класса, […]

Комментарии:

1. Замечательные ответы. вы четко описали этот пункт. Я думаю, что проблема первого маркера заключается в том, что он не разделяет концепцию, то есть где находятся эти места, в которых nested class name может быть текущий экземпляр. Как я уже сказал, предложение всегда заставляет меня читать его так, чтобы nested class name оно рассматривалось как текущее имя, если оно находится в определении, приведенном в первом пуле.