使用& # 39;类# 39;或& # 39;typename& # 39;模板参数?

< p > # EYZ0 < br > # EYZ0 < / p >

在c++中定义函数模板或类模板时,可以这样写:

template <class T> ...

或者你可以这样写:

template <typename T> ...

有充分的理由选择其中一个而不是另一个吗?


我接受了最流行(也是最有趣)的答案,但真正的答案似乎是“不,没有充分的理由更喜欢其中一个而不是另一个。”

  • 它们是等价的(除了下文所述)。
  • 有些人有理由总是使用typename
  • 有些人有理由总是使用class
  • 有些人有理由两者都用。
  • 有些人不在乎他们用的是哪一种。

但是请注意,在c++ 17之前,在模板的模板参数的情况下,需要使用class而不是typename。参见下面的user1428839的回答。(但这种特殊情况不是个人偏好的问题,而是语言的要求。)

296826 次浏览

据我所知,你用哪一种都没关系。在编译器看来,它们是等价的。你喜欢哪个就用哪个。我通常使用class。

Stan Lippman谈到了在这里。我觉得很有趣。

总结: Stroustrup最初使用class在模板中指定类型,以避免引入新的关键字。委员会中的一些人担心这个关键字的过载会导致混乱。后来,委员会引入了一个新的关键字typename来解决语法模糊,并决定让它也被用于指定模板类型以减少混乱,但为了向后兼容,class保留了它的重载含义。

根据Scott Myers, Effective c++(第三版)第42项(当然,这必须是最终答案)-区别是“没有”。

建议是,如果期望T始终是一个类,则使用“class”,如果期望其他类型(int, char*等等)则使用“typename”。把它当作一个用法提示。

我更喜欢使用typename,因为我不喜欢重载关键字(哎呀——对于各种不同的上下文,static有多少不同的含义?)

这一点都不重要,但是class使它看起来像T只能是一个类,而它当然可以是任何类型。typename更准确。另一方面,大多数人使用class,所以这可能更容易阅读。

在响应迈克B,我更喜欢使用'类'作为,在模板中,'typename'有一个重载的含义,但'类'没有。以这个检查型整型为例:

template <class IntegerType>
class smart_integer {
public:
typedef integer_traits<Integer> traits;
IntegerType operator+=(IntegerType value){
typedef typename traits::larger_integer_t larger_t;
larger_t interm = larger_t(myValue) + larger_t(value);
if(interm > traits::max() || interm < traits::min())
throw overflow();
myValue = IntegerType(interm);
}
}

larger_integer_t是一个依赖名称,因此需要在它前面加上“typename”,以便解析器能够识别larger_integer_t是一个类型。另一方面,没有这样的重载含义。

那或者我只是内心懒惰。我输入“class”的频率远远超过“typename”,因此我发现它更容易输入。或者这可能是我写了太多OO代码的标志。

扩展DarenW的评论。

一旦typename和class不被认为有很大不同,严格使用它们可能仍然是有效的。只有当class确实是一个类时才使用class,当它是基本类型时使用typename,例如字符

这些类型实际上也被接受,而不是typename

template<# eyz0 # eyz1 = '/' >

在这种情况下,它甚至优于typename或class。

想想“hintcompleteness”或对其他人的可理解性。实际上,要考虑到第三方软件/脚本可能会试图使用这些代码/信息来猜测模板发生了什么(考虑swig)。

纯粹的历史。# EYZ0:

出现这两个关键词的原因是历史性的。在最初的模板规范中,Stroustrup重用现有的class关键字来指定类型参数,而不是引入可能破坏现有程序的新关键字。这并不是说不考虑一个新的关键字——只是考虑到它潜在的破坏性,它被认为是不必要的。在iso - c++标准之前,这是声明类型参数的唯一方法。

但是应该使用typename而不是! 有关更多信息,请参阅链接,但请考虑以下代码:

template <class T>
class Demonstration {
public:
void method() {
T::A *aObj; // oops ...
};

作为上述所有文章的补充,在处理模板的模板参数时,使用class关键字强制(直到并包括c++ 14),例如:

template <template <typename, typename> class Container, typename Type>
class MyContainer: public Container<Type, std::allocator<Type>>
{ /*...*/ };

在这个例子中,typename Container会生成一个编译器错误,类似这样:

error: expected 'class' before 'Container'

这里有的区别,你应该更喜欢class而不是typename

但是为什么呢?

typename对于模板模板参数来说是非法的,所以为了保持一致,你应该使用class:

template<template<class> typename MyTemplate, class Bar> class Foo { };    //  :(
template<template<class>    class MyTemplate, class Bar> class Foo { };    //  :)