模板中关键字“typename”和“class”的区别?

对于模板,我已经看到了两个声明:

template < typename T >
template < class T >

有什么区别?

在下面的例子中,这些关键字到底是什么意思(取自德语维基百科关于模板的文章)?

template < template < typename, typename > class Container, typename Type >
class Example
{
Container< Type, std::allocator < Type > > baz;
};
255066 次浏览
  1. 没有区别
  2. 模板类型参数Container本身是一个具有两个类型参数的模板。

对于命名模板参数,typenameclass是等价的。§14.1.2:

没有语义差异 在类和typename之间 模板-参数。

typename然而,在使用模板时,在另一个上下文中是可能的-向编译器暗示您引用的是依赖类型。§14.6.2:

模板声明中使用的名称 或定义,这取决于 假定模板参数不 命名类型,除非适用的名称 查找查找类型名称或名称 由关键字typename限定。

示例:

typename some_template<T>::some_type

如果没有typename,编译器通常无法判断您是否引用了一个类型。

虽然没有技术上的区别,但我看到两者用来表示略有不同的东西。

对于应该接受任何类型为T的模板,包括内置(例如数组)

template<typename T>
class Foo { ... }

对于一个仅适用于T是真实类的模板。

template<class T>
class Foo { ... }

但请记住,这纯粹是一些人使用的样式。不是标准强制或编译器强制执行的

typenameclass在指定模板的基本情况下可以互换:

template<class T>
class Foo
{
};

template<typename T>
class Foo
{
};

是相当的。

话虽如此,在某些特定情况下,typenameclass之间存在差异。

第一个是在依赖类型的情况下。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>;

我确信还有其他我错过的案例,但底线是:这两个关键字不相等,这些是一些需要使用一个或另一个的常见案例。

这段片段来自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++的;一些程序员继续专门使用class

使用<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!

在大多数情况下,您不会定义嵌套模板定义,因此任何一个定义都可以——只需在使用中保持一致即可。