对于模板,我看到了这两种声明:

template < typename T >
template < class T >

有什么不同?

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

template < template < typename, typename > class Container, typename Type >
class Example
{
     Container< Type, std::allocator < Type > > baz;
};

当前回答

这段代码摘自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++的;一些程序员继续专门使用类

其他回答

没有区别 Container本身就是一个有两个类型形参的模板。

虽然在技术上没有区别,但我曾看到这两个词被用来表示略有不同的事物。

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

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

对于只适用于T是真实类的模板。

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

但请记住,这只是一些人使用的一种风格。非标准强制或编译器强制的

这段代码摘自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和class是等价的。§14.1.2:

没有语义上的区别 类中的类和typename之间 模板参数。

然而,在使用模板时,Typename在另一个上下文中是可能的——用来提示编译器你引用的是依赖类型。§14.6.2:

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

例子:

typename some_template<T>::some_type

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

Typename和class在指定模板的基本情况下是可以互换的:

template<class T>
class Foo
{
};

and

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>;

我确信我还遗漏了其他一些情况,但底线是:这两个关键字是不相等的,这些是需要使用其中一个的一些常见情况。