Answers:
typename
并且class
是在指定模板的基本情况下可以互换:
template<class T>
class Foo
{
};
和
template<typename T>
class Foo
{
};
是等效的。
话虽如此,在某些情况下,typename
和之间存在差异class
。
第一个是在依赖类型的情况下。typename
用于在引用依赖于另一个模板参数的嵌套类型时进行声明,例如typedef
本示例中的:
template<typename param_t>
class Foo
{
typedef typename param_t::baz sub_t;
};
您实际上在问题中显示的第二个,尽管您可能没有意识到:
template < template < typename, typename > class Container, typename Type >
指定模板模板时,class
必须如上所述使用关键字- 在这种情况下不能与关键字互换(注意:由于C ++ 17在这种情况下都允许使用两个关键字)。typename
class
在显式实例化模板时,还必须使用:
template class Foo<int>;
我确定还有其他情况,但是最重要的是:这两个关键字不相同,这是一些您需要使用其中一个的常见情况。
std::vector<int>::value_type
不是依赖类型,您不需要typename
那里-仅在类型取决于模板参数时才需要它,例如template<class T> struct C { typedef typename std::vector<T>::value_type type; };
param_t
不是依赖类型。依赖类型是依赖于模板参数的名称,例如foo<param_t>::some_type
,不依赖模板参数本身。
GCC 5
,G ++现在允许在模板template参数中使用typename。
用于命名模板参数,typename
并且class
是等效的。第14.1.2条:
模板参数中的类和类型名之间没有语义上的区别。
typename
但是,在使用模板的另一种情况下是可能的-提示编译器您引用的是依赖类型。第14.6.2条:
除非在适用的名称查找中找到类型名称或该名称由关键字typename限定,否则假定模板声明或定义中使用的且依赖于模板参数的名称不会命名类型。
例:
typename some_template<T>::some_type
没有typename
编译器,通常无法判断您是否在引用类型。
虽然没有技术上的差异,但我已经看到两者用来表示略有不同的事物。
对于应该接受任何类型为T的模板,包括内置函数(例如array)
template<typename T>
class Foo { ... }
对于仅在T是实类的情况下才有效的模板。
template<class T>
class Foo { ... }
但是请记住,这纯粹是某些人使用的样式。未由标准强制要求或由编译器强制执行
T t; int i = t.toInt();
),那么你需要一个“真正的阶级”,如果你提供你的代码将无法编译int
的T
...
class
意味着您不仅在期望一个“值”可能支持某些运算符,复制或移动构造和/或赋值,而且还特别需要一种支持某些成员访问语义的类型。然后,快速浏览声明会设置期望值和不鼓励值,例如在class
肯定会出现错误的情况下为参数提供内置类型。
Container
本身就是具有两个类型参数的模板。
template<template<class U> class V> struct C {};
这段代码来自c ++入门书。虽然我确定这是错误的。
每个类型参数必须以关键字class或typename开头:
// error: must precede U with either typename or class
template <typename T, U> T calc(const T&, const U&);
这些关键字具有相同的含义,可以在模板参数列表中互换使用。模板参数列表可以同时使用两个关键字:
// ok: no distinction between typename and class in a template parameter list
template <typename T, class U> calc (const T&, const U&);
使用关键字typename而不是使用类来指定模板类型参数似乎更直观。毕竟,我们可以将内置(非类)类型用作模板类型参数。此外,typename更清楚地指示后面的名称是类型名称。但是,在模板已经广泛使用之后,typename被添加到C ++中。一些程序员继续专门使用类
template <typename T> typename Foo {};
,因为Foo <T>绝对是一类。