template < typename T >
template < class T >
有什么区别?
这个例子中的关键词是什么意思(摘自德语维基百科关于模板的文章)?
template < template < typename, typename > class Container, typename Type >
class Example
{
Container< Type, std::allocator < Type > > baz;
};
typename
和class
在指定模板的基本情况下是可以互换的:
template<class T>
class Foo
{
};
并且
template<typename T>
class Foo
{
};
它们是等价的。
尽管如此,有一些特定情况下typename
和class
有所不同。
第一种情况是依赖类型。例如这个例子中的typedef
,当你引用一个依赖于另一个模板参数的嵌套类型时,需要使用typename
进行声明:
template<typename param_t>
class Foo
{
typedef typename param_t::baz sub_t;
};
你实际上在问题中展示的是第二种情况,尽管你可能没有意识到:template < template < typename, typename > class Container, typename Type >
在指定一个模板模板时,必须像上面一样使用class
关键字--在这种情况下,它与typename
不能互换(注意:自C++17起,这两个关键字都被允许在这种情况下使用)。
在显式实例化模板时,也必须使用class
:
template class Foo<int>;
我相信还有其他情况我没有提到,但归根结底:这两个关键词并不等价,在一些常见情况下你需要使用其中一个。
为了给模板参数命名,typename
和class
是等价的。根据 §14.1.2:
在模板参数中,
class
和typename
之间没有语义上的区别。
然而,在另一种使用模板的情况下,可以使用typename
来提示编译器你正在引用一个依赖类型。根据§14.6.2:
在模板声明或定义中使用的名称,如果依赖于模板参数,则假定该名称不代表类型,除非适用的名称查找找到一个类型名称或该名称由关键字
typename
限定。
举例:
typename some_template<T>::some_type
没有使用typename
,编译器通常无法确定您是否引用了一个类型。
some_template<T>::something * p;
可能是指针声明或乘法。 - Alex Che虽然在技术上没有区别,但我看到两者用于表示略有不同的东西。
对于一个应该接受任何类型T(包括内置类型如数组)的模板:
template<typename T>
class Foo { ... }
对于仅在T为实类时有效的模板。
template<class T>
class Foo { ... }
但请记住,这只是一种风格,有些人使用它,但它并非由标准规定或编译器强制执行。
T t; int i = t.toInt();
),那么你需要一个“真正的类”,如果你为T
提供了int
,你的代码将无法编译。 - Steve Jessopclass
意味着你不仅期望一个“值”,可能支持一些运算符、复制或移动构造和/或赋值,而且特别需要一个支持一些成员访问语义的类型。快速浏览声明就可以设置期望,并阻止例如为 class
参数提供内置类型,当然这肯定是一个错误。 - Tony DelroyContainer
本身是一个带有两个类型参数的模板。
template<template<class U> class V> struct C {};
- Georg Fritzsche<typename T>
和 <class T>
并没有区别,它是 C++ 程序员使用的惯例。我个人更喜欢 <typename T>
,因为它更清晰地描述了其用途;即使用特定类型定义模板。class
(而不是 typename
)。template <template <typename> class T> class C { }; // valid!
template <template <typename> typename T> class C { }; // invalid!
这段代码片段来自于C++ Primer书籍。虽然我确信这是错误的。
每个类型参数必须以关键字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而不是class来指定模板类型参数似乎更直观。毕竟,我们可以使用内置(非类)类型作为模板类型参数。此外,typename更清楚地表示后面的名称是类型名称。然而,typename是在模板已经广泛使用之后添加到C++中的;一些程序员仍然专门使用class。
std::vector<int>::value_type
不是一个依赖类型,因此您不需要在那里使用typename
- 只有在类型取决于模板参数时才需要使用,例如template<class T> struct C { typedef typename std::vector<T>::value_type type; };
。 - Georg Fritzscheparam_t
不是一个相关类型(dependent type)。 相关类型指的是依赖于模板参数的名称,例如foo<param_t>::some_type
,而不是模板参数本身。 - Georg Fritzschetypename
,即template <typename> typename C
。 - user4112979GCC 5
开始,G++现在允许在模板模板参数中使用typename关键字. - Chnossos