#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
Имя ссылается на текущий экземпляр, если оно
- в определении шаблона класса, вложенного класса шаблона класса, члена шаблона класса или члена вложенного класса шаблона класса, введенное имя класса шаблона класса или вложенного класса,
- в определении шаблона основного класса или члена шаблона основного класса имя шаблона класса, за которым следует список аргументов шаблона основного шаблона (как описано ниже), заключенный в <> (или эквивалентный шаблон псевдоним специализация),
- в определении вложенного класса шаблона класса имя вложенного класса, на которое ссылаются как на член текущего экземпляра, или
Объявление 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
оно рассматривалось как текущее имя, если оно находится в определении, приведенном в первом пуле.