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

Mat*_*Mat 456 c++ templates keyword

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

template < typename T >
template < class T >
Run Code Online (Sandbox Code Playgroud)

有什么不同?

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

template < template < typename, typename > class Container, typename Type >
class Example
{
     Container< Type, std::allocator < Type > > baz;
};
Run Code Online (Sandbox Code Playgroud)

Aar*_*otz 401

typename并且class在指定模板的基本情况下可以互换:

template<class T>
class Foo
{
};
Run Code Online (Sandbox Code Playgroud)

template<typename T>
class Foo
{
};
Run Code Online (Sandbox Code Playgroud)

是等价的.

话虽如此,有些特定情况下typename和之间存在差异class.

第一个是依赖类型的情况.typename用于在引用依赖于另一个模板参数的嵌套类型时声明,例如typedef在此示例中:

template<typename param_t>
class Foo
{
    typedef typename param_t::baz sub_t;
};
Run Code Online (Sandbox Code Playgroud)

你在问题中实际显示的第二个,尽管你可能没有意识到:

template < template < typename, typename > class Container, typename Type >
Run Code Online (Sandbox Code Playgroud)

在指定模板模板时,class必须按上述方式使用关键字 - 在这种情况下它不可互换(注意:由于C++ 17在这种情况下允许两个关键字).typename

您还必须class在显式实例化模板时使用:

template class Foo<int>;
Run Code Online (Sandbox Code Playgroud)

我确信还有其他一些我错过的情况,但最重要的是:这两个关键字并不相同,而且这些是您需要使用其中一个的常见情况.

  • 最后一个是一个特殊情况,你必须使用类或结构,而不是typename来定义一个类.显然,你的前两位代码都不能用`template <typename T> typename Foo {};`来代替,因为Foo <T>绝对是一个类. (39认同)
  • 从[`GCC 5`](https://gcc.gnu.org/gcc-5/changes.html)开始,_G ++现在允许在模板模板parameter_中使用typename. (4认同)
  • `std :: vector <int> :: value_type`不是依赖类型,你不需要`typename` - 你只需要一个类型依赖于模板参数,比如`template <class T> struct C {typedef typename std :: vector <T> :: value_type type; };` (2认同)
  • 而且,`param_t`不是依赖类型.依赖类型是依赖于模板参数*的*名称,例如`foo <param_t> :: some_type`,而不是模板参数本身. (2认同)
  • C++ 1z提案[N4051](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4051.html)将允许您使用`typename`,即`模板<typename> typename C`. (2认同)

Geo*_*che 87

用于命名模板参数,typename并且class是等效的.§14.1.2:

template-parameter中的class和typename之间没有语义差异.

typename但是在使用模板时可能在另一个上下文中 - 提示您正在引用依赖类型的编译器.§14.6.2:

假定模板声明或定义中使用的名称以及依赖于模板参数的名称不会命名类型,除非适用的名称查找找到类型名称或名称由关键字typename限定.

例:

typename some_template<T>::some_type
Run Code Online (Sandbox Code Playgroud)

没有typename编译器一般不能告诉你是否指的是类型.

  • 我理解规则,但究竟是什么阻止编译器在内部将 some_template&lt;T&gt; 视为类型?对不起,如果我遗漏了一些明显的东西。 (4认同)
  • @batbrat [此处](/sf/answers/42919271/) 是关于该主题的详细答案。例如,`some_template&lt;T&gt;::something * p;` 可以是指针声明或乘法。 (2认同)

Mic*_*son 22

虽然没有技术差异,但我看到这两个用来表示略有不同的东西.

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

template<typename T>
class Foo { ... }
Run Code Online (Sandbox Code Playgroud)

对于仅在T是真实类的情况下才能工作的模板.

template<class T>
class Foo { ... }
Run Code Online (Sandbox Code Playgroud)

但请记住,这纯粹是一些人使用的风格.不是由标准强制要求或由编译器强制执行

  • 我并没有责怪你提及它,但我认为这个政策是错误的,因为程序员最终会花时间思考一些无关紧要的事情("我使用过正确的吗?")来表明某些事情没有重要("是否存在实现此模板参数所需接口的内置类型?").如果使用了模板参数的任何成员(`T t; int i = t.toInt();`),那么你需要一个"真正的类",如果你为`T提供`int`你的代码将无法编译`... (13认同)
  • 由于它们的意思相同,请仅使用一个。否则,就像使用内联 {,除非是星期二,然后您使用下一行 {。 (3认同)

小智 9

<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!
Run Code Online (Sandbox Code Playgroud)

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

  • 从 C++17 开始,这两个定义均有效 (6认同)

Nik*_*sov 6

  1. 没有不同
  2. 模板类型参数Container本身是具有两个类型参数的模板.

  • 总体上有所不同。 (3认同)
  • @Mat:是的,要搜索的术语是*模板模板参数/参数*.例如:`template <template <class U> class V> struct C {};` (2认同)

K.K*_*K.K 5

这段代码来自c ++入门书。虽然我确定这是错误的。

每个类型参数必须以关键字class或typename开头:

// error: must precede U with either typename or class
template <typename T, U> T calc(const T&, const U&);
Run Code Online (Sandbox Code Playgroud)

这些关键字具有相同的含义,可以在模板参数列表中互换使用。模板参数列表可以同时使用两个关键字:

// ok: no distinction between typename and class in a template parameter list
template <typename T, class U> calc (const T&, const U&);
Run Code Online (Sandbox Code Playgroud)

使用关键字typename而不是使用class来指定模板类型参数似乎更直观。毕竟,我们可以将内置(非类)类型用作模板类型参数。此外,typename更清楚地指示后面的名称是类型名称。但是,在模板已经广泛使用之后,typename被添加到C ++中。一些程序员继续专门使用类