2010-12-12 2 views
19

Рассмотрима этого кода,Использования TYPENAME ключевого слова с ЬурейиМ и нового

template<class T> 
struct Sample 
{ 
    typename T::X *x; //declare pointer to T's X 
}; 

В приведенной выше коде, ключевое слово typename требуется компилятор, так что он может неоднозначность между вложенными типами и вложенными значениями в шаблонах. Это означает, что при отсутствии typename ключевого слова, компилятор будет интерпретировать это как умножение T :: X с й,

T::X *x; //multiply T::X with x 

Таким образом, в таких ситуациях, когда может возникнуть неопределенность, ключевое слово typename становится необходимости так, чтобы устранить неоднозначность. Но есть несколько ситуаций, когда сам контекст устраняет двусмысленности. В other topic обсуждаются контексты базового класса и функциональных параметров (последнее не устраняет неоднозначности). В этой теме, я особенно хочу обсудить два других контексты, которые кажутся однозначна, но мы все еще должны написать typename,

typedef typename T::X xtype; 
pX = new typename T::X; 

В этих двух ситуациях, ключевые слова typedef и new дают понять достаточно для компилятора, что все, что следует за ним, это тип, незначение.

Так что мой вопрос в том, почему компиляторы все еще нуждаются в ключевом слове typename, даже в недвусмысленных ситуациях, например, когда мы используем typedef и new?


EDIT (после прочтения этого ответа от Johannes Schaub):

//typedef NOT followed by a type! 
int typedef A; 

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

Рассмотрим это,

T::X typedef *x; 

Так из контекста, это все еще достаточно ясно компилятору, что T :: X представляет собой тип, независимо от того, появляется ли он перед темtypedef или послеtypedef , Если C++ не позволяет писать typedef 5 five или typedef T::value t_value (где T :: значение значение), наличие typedef сами удаляют все двусмысленности и так, typename, кажется ненужным требование Стандарта (в таких ситуациях). Тот же аргумент справедлив и для new.


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

struct A 
{ 
     struct X { string name; }; 
     static const int X = 100; 
}; 

Я особенно хочу знать, если следующий код (из конструкторы) является правильным (переноснымы) или нет,

//two interesting statements 
pX = new typename T::X; //T::X means struct X 
product = T::X * p; //but here, T::X means int X 

Полный код here на ideone. Пожалуйста, взгляните на него перед ответом. :-)

+0

И вопрос в том, что? –

+0

его вопрос в том, почему компилятору требуется ключевое слово 'typename' после' typedef'. потому что после 'typedef' он всегда знает, что typeString - Commin. Однако я думаю, что так написано синтаксический анализатор. –

+0

@Pawel: вопрос в следующем: зачем компиляторам по-прежнему нужно ключевое слово typename в однозначных ситуациях? – Nawaz

ответ

0

Тогда зачем компиляторам по-прежнему требуется ключевое слово typename?

Поскольку правила языка сформулированы таким образом: каждый зависимый имя, которое используется в контексте типа должны предшествовать typename (с соответствующими изменениями, то же самое справедливо и для имени шаблона и template ключевого слова) , Итак, почему правила языка не имеют значения между случаями, когда требуется имя типа для устранения двусмысленности и тех, где контекст предоставляет достаточную информацию? Наверное, меня не было, когда было принято решение - чтобы содержание описания языка было еще более сложным (рассмотрите последствия недостающих случаев, так или иначе).

В вашем примере, X не является именем типа (такая возможность, если для совместимости с C, где имя тега автоматически не вводите имя), так что вам нужно yuse struct:

pX = new struct T::X; 
0

Ваш код кажется, идет в очень серой области.

Этот пункт по имени скрывающего

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

, похоже, указывает, что компилятор прав, чтобы жаловаться, что A::X не является именем типа.

+1

это не убедительно, поскольку любой компилятор подсказок может получить от использования 'typename' (в этих двух случаях), тот же самый намек, который может получить компилятор даже от использования' typedef' и 'new'. – Nawaz

+1

@Nawaz: Меня больше интересовало скрытие имени. 'struct X {}; int X; typedef X Y; '- компилятор видит только целое число X. AProgrammer на что-то, хотя, потому что' typedef struct X Y; '" отображает "это". – UncleBens

+0

, даже в этом случае 'typedef' и' new' могут играть ту же роль, которую вы ожидаете от 'typename'. Идея 'typename' заключается в том, чтобы дать подсказку компилятору, что все, что следует, это' type', то этот компилятор подсказок уже может получить, когда он анализирует ключевые слова 'typedef' или' new'. – Nawaz

14

Синтаксис C++ более сумасшедший.

// typedef NOT followed by a type! 
int typedef A; 

// new NOT followed by a type! 
new (0) int; 

Другие прокомментировали ваш пример. Спецификатор typename не дает поиска, игнорируя имена, отличные от типа. Так что если вы скажете new typename T::X, и есть имя объекта X в T, оно все равно будет найдено вместо имени типа X (однако GCC игнорирует имена не-типа при поиске имени после typename, но это не соответствует стандартам) ,


Ответы на редактирование:

Рассмотрим это,

T::X typedef *x; 

Так из контекста, это все еще достаточно ясно компилятору, что T :: X представляет собой тип, независимо от того, появляется ли она до typedef или после typedef.

компилятор должен знать, когда декларация спецификаторы и (то есть «тип раздела» и когда начало описатель раздел (т.е. раздел «Имена») Есть заявления, где раздел типа пуст:.

.
// constructor definitions don't need a type section 
MyClass::MyClass() { } 

// conversion function definitions don't need a type section 
MyClass::operator int() { } 

Если первое задаваемое имя не является типа, секция типа заканчивается, и начинается раздел имени Высказывания T::X говорит компилятор:.

Теперь я хочу, чтобы определить T::X

Он читается слева направо, поэтому он подумает, что вы забыли точку с запятой, когда она встречает typedef. Внутри классов интерпретация немного отличается, но тоже такая. Это простой и эффективный анализ.

Тот же аргумент справедлив и для новых.

Я с вами согласен. Синтаксически это должно быть однозначно , если вы оставляете круглые скобки. Поскольку я никогда не писал парсер C++, могут быть скрытые ловушки, которых я не вижу.

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

+0

Спасибо за это ценное сообщение. По крайней мере, сегодня я узнал этот новый синтаксис typedef. Но я думаю, что он до сих пор не отвечает на мой вопрос удовлетворительно. Пожалуйста, прочитайте отредактированную часть в моем сообщении! – Nawaz