“typename”和“class”模板参数有什么区别?

What is the difference between "typename" and "class" template parameters?

提问人:Mat 提问时间:1/8/2010 最后编辑:Jan SchultkeMat 更新时间:9/23/2023 访问量:288800

问:

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

template < typename T >
template < class T >

有什么区别?

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

template < template < typename, typename > class Container, typename Type >
class Example
{
     Container< Type, std::allocator < Type > > baz;
};
C++ 模板 关键字

评论


答:

11赞 Nikolai Fetissov 1/8/2010 #1
  1. 没有区别
  2. 模板类型参数本身是具有两个类型参数的模板。Container

评论

4赞 Hassan Syed 1/8/2010
一般来说是有区别的。
0赞 Mat 1/8/2010
容器模板化的这两个参数是否也可以命名?在此示例中,它们没有任何名称。而且 - 在这个例子中,它被写成“class Container” - 是否也可以写成“typename Container”?
2赞 Georg Fritzsche 1/8/2010
@Mat:是的,要搜索的术语是模板模板参数/参数。例如:template<template<class U> class V> struct C {};
129赞 Georg Fritzsche 1/8/2010 #2

用于命名模板参数,并且是等效的。§14.1.2:typenameclass

没有语义差异 在 class 和 typename 之间 template-参数。

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

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

例:

typename some_template<T>::some_type

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

评论

8赞 batbrat 3/28/2019
我理解这个规则,但究竟是什么阻止了编译器在内部将 some_template<T> 视为一种类型?对不起,如果我遗漏了一些明显的东西。
6赞 Alex Che 9/28/2020
@batbrat 这是关于该主题的详细答案。例如,可以是指针声明或乘法。some_template<T>::something * p;
0赞 batbrat 9/28/2020
谢谢@AlexChe我会通过链接!
37赞 Michael Anderson 1/8/2010 #3

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

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

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

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

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

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

评论

23赞 Steve Jessop 1/8/2010
我不怪你提到它,但我认为这个策略是相当误导的,因为程序员最终会花时间思考一些无关紧要的事情(“我是否使用了正确的?”)来指示一些无关紧要的事情(“是否存在一个内置类型来实现此模板参数所需的接口?如果使用了模板参数的任何成员 (),那么你需要一个“真正的类”,如果你提供 ...T t; int i = t.toInt();intT
1赞 Potatoswatter 1/8/2010
如果要将使用限制为实际类,最好添加专用化以引发/导致非类类型的错误。如果要将使用限制为特定类,请仅针对它们进行专精。无论如何,这种风格上的区别太微妙了,无法传达信息。
4赞 Paul Draper 10/8/2014
由于它们的意思相同,请只使用一个。否则,就像使用 inline {,除非是星期二,然后你使用 next-line {.
1赞 Tony Delroy 7/7/2015
+1 我有时自己会这样做...... 这意味着您不仅期望一个“值”可能支持某些运算符、复制或移动构造和/或赋值,而且特别需要一个支持某些成员访问语义的类型。然后,对声明的最快速浏览会设定期望并阻止,例如,为参数提供内置类型,而这肯定是错误的。classclass
1赞 lfalin 11/24/2015
我想了解在现实世界中存在哪些情况,其中模板适用于任何类,但不适用于内置类型。你有例子吗?
602赞 Aaron Klotz 1/8/2010 #4

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

template<class T>
class Foo
{
};

template<typename T>
class Foo
{
};

是等价的。

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

第一个是依赖类型。 用于在引用依赖于另一个模板参数的嵌套类型时声明,如本例中的 :typenametypedef

template<typename param_t>
class Foo
{
    typedef typename param_t::baz sub_t;
};

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

template < template < typename, typename > class Container, typename Type >

指定模板模板时,必须如上所述使用关键字 - 在这种情况下它不能互换(注意:由于 C++17 在这种情况下允许使用这两个关键字)。classtypename

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

template class Foo<int>;

我敢肯定我错过了其他情况,但底线是:这两个关键字并不等价,这些是您需要使用其中一个的常见情况。

评论

72赞 Steve Jessop 1/8/2010
最后一个几乎是必须使用 class 或 struct(而不是 typename)来定义类的特例。显然,你的前两位代码都不能用 替换,因为 Foo<T> 绝对是一个类。template <typename T> typename Foo {};
3赞 Georg Fritzsche 1/8/2010
std::vector<int>::value_type不是一个依赖类型,你不需要那里 - 你只需要它,比如说一个类型依赖于模板参数typenametemplate<class T> struct C { typedef typename std::vector<T>::value_type type; };
2赞 Georg Fritzsche 1/27/2010
同样,不是依赖类型。依赖类型是依赖于模板参数的名称,例如,而不是模板参数本身。param_tfoo<param_t>::some_type
2赞 user4112979 10/6/2014
C++1z 提案 N4051 将允许您使用 ,即 。typenametemplate <typename> typename C
4赞 Chnossos 11/8/2014
GCC 5 开始,G++ 现在允许在模板模板参数中使用 typename
7赞 K.K 12/8/2012 #5

这段代码来自 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 更清楚地表明后面的名称是类型名称。但是,在模板已经广泛使用之后,类型名被添加到 C++ 中;一些程序员继续专门使用类

9赞 Gurpreet Singh 1/13/2021 #6

使用 OR 没有区别;即它是C++程序员使用的约定。我自己更喜欢它,因为它更清楚地描述了它的用途;即定义具有特定类型的模板。<typename T><class T><typename T>

注意:有一个例外,在声明模板模板参数时,您必须使用(而不是):classtypename

template <template <typename> class    T> class C { }; // valid!

template <template <typename> typename T> class C { }; // invalid!

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

评论

5赞 Eduard Rostomyan 1/4/2022
这两个定义自 C++ 起有效 17