对于模板,我已经看到了两个声明:
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
之间存在差异。
第一个是依赖类型的情况。 typename
用于在您引用依赖于另一个模板参数的嵌套类型时声明,例如本示例中的 typedef
:
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:
模板参数中的类和类型名之间没有语义差异。
typename
但是,在使用模板时可以在另一个上下文中使用 - 提示编译器您指的是依赖类型。 §14.6.2:
在模板声明或定义中使用并且依赖于模板参数的名称被假定为不命名类型,除非适用的名称查找找到类型名称或该名称由关键字 typename 限定。
例子:
typename some_template<T>::some_type
如果没有 typename
,编译器通常无法判断您是否指的是类型。
some_template<T>::something * p;
可以是指针声明或乘法。
虽然没有技术上的区别,但我看到这两者用来表示略有不同的事物。
对于应该接受任何类型为 T 的模板,包括内置函数(例如数组)
template<typename T>
class Foo { ... }
对于仅适用于 T 是真实类的模板。
template<class T>
class Foo { ... }
但请记住,这纯粹是一些人使用的风格。标准未强制要求或编译器强制执行
T t; int i = t.toInt();
),那么您需要一个“真正的类”,如果您为 T
提供 int
,您的代码将无法编译...
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 而不是 class 来指定模板类型参数似乎更直观。毕竟,我们可以使用内置(非类)类型作为模板类型参数。而且,typename 更清楚地表明后面的名称是类型名称。然而,在模板已经广泛使用之后,typename 被添加到 C++ 中。一些程序员继续独占使用类
使用 <typename T>
OR <class T>
没有区别;即,它是 C++ 程序员使用的约定。我自己更喜欢 <typename T>
,因为它更清楚地描述了它的用途;即定义具有特定类型的模板。
注意:在声明模板模板参数时,您必须使用 class
(而不是 typename
)有一个例外:
template <template <typename> class T> class C { }; // valid!
template <template <typename> typename T> class C { }; // invalid!
在大多数情况下,您不会定义嵌套模板定义,因此任何一个定义都可以工作——只是在您的使用中保持一致。
template <typename T> typename Foo {};
替换,因为 Foo<T>绝对是一个类。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
,而不是模板参数本身。typename
,即template <typename> typename C
。GCC 5
开始,G++ 现在允许在模板模板参数中使用 typename。