我仔细阅读了许多关于这个主题的答案,但是我仍然无法确定在嵌套模板类的非模板函数作用域中确切地需要或不需要这两个关键字。
我的参考编译器是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
。 - Johannes Schaub - litbtypename
的规则。可能是在发布 gcc 4.9 后。可以解释一下第三个例子吗? - Bo PerssonPa<double>::Pe<BBB>
是一个依赖名称,因为它的类型取决于BBB
。但这并不意味着您必须插入typename
。对于Pa<AAA>::Pe<int>
和Pa<AAA>
也是如此。在所有这些情况下,编译器可以自行确定Pe
是一个模板,而Pe<int>
/Pe<BBB>
是一个类型。请参见https://dev59.com/dHRB5IYBdhLWcg3weXOX#17579889。 - Johannes Schaub - litb