Использование однозначных выражений "template" и "typename", когда они не нужны - PullRequest
7 голосов
/ 03 апреля 2012

Этот вопрос касается того, когда и почему в коде шаблона C ++ требуются typename и template.нужен в C ++ 03?Как насчет C ++ 11?

1 Ответ

11 голосов
/ 03 апреля 2012

Это допустимо в соответствующих компиляторах C ++ 03 / C ++ 11 для некоторого определения «действительный».

C ++ 03 ISO / IEC 14882: 2003 §14.2.5:

[ Примечание: Как и в случае с префиксом typename, префикс template допускается в тех случаях, когда это не является строго обязательным;то есть, когда выражение слева от -> или . или спецификатор вложенного имени не зависит от шаблона-параметра .]

C ++ 11 ИСО / МЭК 14882: 2011 §14.2.5:

[ Примечание: Как и в случае с *Префикс 1024 *, префикс template разрешен в случаях, когда это не является строго обязательным;то есть когда спецификатор вложенного имени или выражение слева от -> или . не зависит от шаблона-параметра , или использование непоявляются в объеме шаблона.- конец примечания ]

Обратите внимание, что вы не можете использовать template, когда рассматриваемый элемент на самом деле не является шаблоном - вы не можете лгать с ним,Также обратите внимание, что для typename тип должен быть квалифицированным типом (например, X::Y, а не просто X).C ++ 11 также изменил его, чтобы вам не нужно было находиться в области действия шаблона, тогда как C ++ 03 требовал, чтобы вы были в шаблоне.Также обратите внимание, что компиляторы могут различаться в зависимости от того, позволяют ли они делать это.Например, под Clang это предупреждает под флагом -Wc++11-extensions.


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

struct X {
    typedef int Y;
    template <typename T> static void foo();
    static void bar();
    template <typename T> static void baz(T);
};

Недопустимо в обоих C ++ 03и C ++ 11:

template <typename T>
void foo() {
    typename int z = 0; // int is not a qualified name.
    X::template bar();  // X::bar is not a template.
    X::template baz(z); // no template argument list.
}

Недопустимо в C ++ 03, допустимо в C ++ 11 (но выдает предупреждение для моей копии Clang):

void bar() {
    typename X::Y z = 0;    // not in the body of a template, so
    X::template foo<int>(); // no possibility of dependent names.
}

Действителени в C ++ 03, и в C ++ 11:

template <typename T>
void baz() {
    typename X::Y z = 0;    // not a dependent name, so 'typename'
    X::template foo<int>(); // isn't strictly necessary.
}
...