你为什么有时需要写'typename T`而不只是`T`?

Sta*_*ked 10 c++ sfinae

我正在阅读有关SFINAE的维基百科文章,并遇到以下代码示例:

struct Test 
{
    typedef int Type;
};

template < typename T > 
void f( typename T::Type ) {} // definition #1

template < typename T > 
void f( T ) {}                // definition #2

void foo()
{
    f< Test > ( 10 ); //call #1 

    f< int > ( 10 );  //call #2 without error thanks to SFINAE
}
Run Code Online (Sandbox Code Playgroud)

现在我实际上已经编写了这样的代码,并且在某种程度上直觉上我知道我需要输入"typename T"而不是"T".但是,了解它背后的实际逻辑会很高兴.有人在乎解释吗?

jal*_*alf 13

typename X::YX是或取决于模板参数时需要执行的简短版本.在X已知之前,编译器无法判断Y是类型还是值.所以你必须添加typename以指定它是一种类型.

例如:

template <typename T>
struct Foo {
  typename T::some_type x; // T is a template parameter. `some_type` may or may not exist depending on what type T is.
};

template <typename T>
struct Foo {
  typename some_template<T>::some_type x; // `some_template` may or may not have a `some_type` member, depending on which specialization is used when it is instantiated for type `T`
};
Run Code Online (Sandbox Code Playgroud)

正如sbi在评论中指出的那样,歧义的原因Y可能是静态成员,枚举或函数.在不知道类型的情况下X,我们无法分辨.该标准指定编译器应假定它是一个值,除非使用typename关键字明确标记为类型.

听起来像评论者真的希望我提到另一个相关案例:;)

如果从属名称是函数成员模板,并且您使用显式模板参数(foo.bar<int>()例如)调用它,则必须template在函数名称之前添加关键字,如foo.template bar<int>().

原因是如果没有template关键字,编译器会假定它bar是一个值,并且您希望在其上调用less than运算符(operator<).


Ale*_*lli 9

一般来说,C++的语法(继承自C)有一个技术缺陷:解析器必须知道某些东西是否是一个类型,否则它只是无法解决某些歧义(例如,是X * Y乘法,或指针的声明) Y到X类型的对象?这一切都取决于X是否命名类型......! - ).该typename"形容词"让您作出这样的非常清楚和明确需要时(正如另一种答案提到的,是典型的当模板参数都参与;-).