Я внимательно прочитал много ответов, касающихся этой темы, но, тем не менее, я не могу ТОЧНО понять, когда эти два ключевых слова ЯВЛЯЮТСЯ или НЕ нужны в рамках функции, не являющейся шаблоном, которая является членом вложенного класса шаблона.
Моими эталонными компиляторами являются GNU g++ 4.9.2 и clang 3.5.0.
Они почти не отличаются в следующем коде, где я помещаю встроенные комментарии, пытаясь объяснить, что происходит.
#include <iostream>
// a simple template class with a public member template struct
template <class Z>
class Pa
{
// anything
public:
template <class U>
struct Pe // a nested template
{
// anything
void f(const char *); // a non-template member function
};
template <class U> friend struct Pe;
};
// definition of the function f
template <class AAA>
template <class BBB>
void Pa<AAA> :: Pe<BBB> :: f(const char* c)
{
Pa<AAA> p; // NO typename for both clang and GNU...
// the following line is ACCEPTED by both clang and GNU
// without both template and typename keywords
// However removing comments from typename only
// makes clang still accepting the code while GNU doesn't
// accept it anymore. The same happens if the comments of template
// ONLY are removed.
//
// Finally both compilers accept the line when both typename AND
// template are present...
/*typename*/ Pa<AAA>::/*template*/ Pe<BBB> q;
// in the following clang ACCEPTS typename, GNU doesn't:
/*typename*/ Pa<AAA>::Pe<int> qq;
// the following are accepted by both compilers
// no matter whether both typename AND template
// keywords are present OR commented out:
typename Pa<int>::template Pe<double> qqq;
typename Pa<double>::template Pe<BBB> qqqq;
std::cout << c << std::endl; // just to do something...
}
int main()
{
Pa<char>::Pe<int> pp;
pp.f("bye");
}
Итак, в рамках f
является ли Pa<double>::Pe<BBB>
зависимым именем или нет?
А как же Pa<AAA>::Pe<int>
?
И, в конце концов, почему такое разное поведение двух цитируемых компиляторов?
Кто-нибудь может пояснить решение загадки?
typename
илиtemplate
и забываете о том, чтоP<AAA>
является окружающим шаблоном. Я думаю, что у GCC есть ошибка, и я рекомендую сделать PR. Здесь нет необходимости вtypename
илиtemplate
. - person Johannes Schaub - litb   schedule 03.09.2015typename
там, где это строго не требуется. Вероятно, после выпуска gcc 4.9. Можно пояснить пример 3. - person Bo Persson   schedule 03.09.2015Pa<double>::Pe<BBB>
является зависимым именем в том смысле, что его тип зависит отBBB
. Но это не значит, что вы должны вставлятьtypename
. Это верно также дляPa<AAA>::Pe<int>
иPa<AAA>
. Во всех этих случаях компилятор может сам определить, чтоPe
— это шаблон, аPe<int>
/Pe<BBB>
— это тип. См. stackoverflow.com/a/17579889/34509. - person Johannes Schaub - litb   schedule 03.09.2015