2012-02-03 6 views
1

Я читал листке по этому адресуКак утверждение T :: x (y) неоднозначно, если T является аргументом шаблона?

http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fkeyword_typename.htm

, и я понял, что я понятия не имею, какой тип T :: х может представлять возможно. Вот это ВЫПИСКА

template<class T> class A 
{ 
    T::x(y); 
    typedef char C; 
    A::C d; 
} 

Оператор T :: х (у) неоднозначна. Это может быть вызов функции x() с нелокальным аргументом y или может быть объявлением переменной y с типом T :: x. C++ интерпретирует это утверждение как вызов функции. Чтобы компилятор интерпретировал этот оператор как объявление , вы должны добавить ключевое слово typename в начало . Утверждение A :: C d; плохо сформирован. Класс A также относится к A и, следовательно, зависит от параметра шаблона. Вы должны добавить имя типа ключевое слово в начале этого заявления:

Я хотел бы понять, как может быть переменной у типа Т :: х, как бы эта работа, и что это могло бы означать? Что будет x?

Спасибо :-)

ответ

6

Как прогрев до моего полного ответа, необходимо учитывать следующее:

template <typename T> void IterateOverContainer(T container) { 
    /* Error! */ 
    T::iterator itr(container.begin()); 
} 

Здесь iterator тип вложен в T; например, std::vector<int>::iterator. Чтобы избежать двусмысленностей здесь, то typename ключевого слова становится необходимым:

template <typename T> void IterateOverContainer(T container) { 
    /* Now good! */ 
    typename T::iterator itr(container.begin()); 
} 

Теперь это «ясно» имя типа (это то, что typename средства!), Так что ясно, что мы хотим объявить переменную вместо вызова функция.

Тем не менее, с новым C++ 11 функций, вы можете обойти это полностью с auto:

template <typename T> void IterateOverContainer(T container) { 
    auto itr(container.begin()); 
} 

Или, более ясно:

template <typename T> void IterateOverContainer(T container) { 
    auto itr = container.begin(); 
} 

Теперь, как на ваш вопрос: как Может ли T::x(y) объявить переменную? Ну, из-за странной причуде C, это совершенно законно объявление переменной:

int (x); 

Это то же самое, как

int x; 

Так что, если у нас было что-то вроде этого:

template <typename T> void IterateOverContainer(T container) { 
    /* Error! */ 
    T::iterator(itr); 
} 

Это может быть интерпретировано как объявление переменной с именем itr типа T::iterator или в качестве вызова функции T::iterator, проходящей itr a s параметр. Использование typename неоднозначно, какой он есть.

Интересно, что это положение для дополнительных круглых скобок является той же причиной, что и Most Vexing Parse. Надеюсь, вы никогда не столкнетесь с этим. :-)

Надеюсь, это поможет!

+0

Похоже, что ваша учетная запись была сделана, чтобы ответить на этот вопрос :) –

+0

Всего несколько простых вопросов, если я определяю класс внутри другого (x внутри Y). Это будет тип Y :: x? Я думаю, что нижний регистр x - это то, что меня отбросило, я не понимал, что это вложенный класс, если это так. Также T :: iterator itr (container.begin()); построение типа, как иначе это можно интерпретировать? Sry для моего невежества по теме – rubixibuc

+0

@ rubixibuc- (Обратите внимание, что я немного обновил свой ответ, прежде чем получил это сообщение, поэтому вы можете прочитать конец моего редактирования). Я не уверен, что понимаю, что вы подразумеваете под «конструированием типа»; вы можете уточнить? – templatetypedef

0

Как уже говорилось, T::x может означать «x типа (возможно, class или typedef), который определен в T. Это может также означать» указатель на функцию x член ЕС, T «s.

Часто компилятор часто может определить, что правильно на основе определенных сигналов (вы пишете T::x foo или void (T::*)() foo = T::x?); Visual Studio делает, и GCC использовал (они остановились, потому что в то время люди могли бы скомпилировать свой код на GCC, но не на Visual Studio). Для стандартизации требуется typename для устранения неоднозначности жестких дел.