为什么结构体不允许在模板定义中使用?

4
以下代码出现错误:error: ‘struct Foo’ is not a valid type for a template constant parameter:
template <struct Foo>
struct Bar {

};

为什么会这样呢?
template <class Foo>
struct Bar {

};

这个功能完全正常,甚至可以接受一个结构体作为参数。


1
因为C++语言将其定义为这样,要么使用class,要么使用typename,从我的角度来看,typename更能描述正在发生的事情,否则人们会尝试用struct替换它,原因不明... template <typename Foo>意味着有一个我将称之为Footype,它将在编译期间被实际使用的类型所替换... - stefanB
4个回答

10
这只是语法规则的产物——语法允许您使用"class"或"typename"关键字来指示类型模板参数。否则,参数必须是一个“非类型”模板参数(基本上是整数、指针或引用类型)。
我想Stroustrup(和其他可能提供意见的人)认为没有必要包括"struct"作为指示类型模板参数的关键字,因为不需要与C向后兼容。
实际上,我的回忆是,当添加"typename"以指示模板类型参数时,Stroustrup 希望取消使用"class"关键字(因为它很令人困惑),但有太多依赖它的代码。

编辑:

事实证明,故事更像是(来自Stan Lippman的博客文章):

两个关键字的原因是历史性的。在最初的模板规范中,Stroustrup重用了现有的class关键字来指定类型参数,而不是引入一个可能会破坏现有程序的新关键字。并不是说没有考虑过新关键字——只是考虑到其潜在的破坏性,认为没有必要引入新关键字。直到ISO-C++标准出现之前,这是声明类型参数的唯一方式。
重用现有关键字似乎总是会引起混淆。我们发现初学者们会想知道使用class是否限制了用户可以指定的类型参数为类类型,而不是内置类型或指针类型。因此,有一些人认为没有引入新关键字是一个错误。
在标准化期间,在模板定义中发现了某些构造,它们解析为表达式,尽管它们本来是用来表示声明的。
委员会决定引入一个新关键字,以摆脱编译器对表达式的不幸沉迷。这个新关键字就是自描述的typename。
既然这个关键字已经在工资单上了,那么为什么不修复由于重用class关键字而引起的混淆呢?当然,考虑到现有代码、书籍、文章、演讲和帖子的广泛体量使用了class关键字,他们选择保留对该关键字的支持。这就是为什么你有两个关键字的原因。

自从我能记事以来,我一直在使用template <typename ...>,我相信class部分会让人们感到困惑,认为它是实际的class,因此他们想把struct放进去,这是很奇怪的... - stefanB
2
在他的C++0x FAQ (http://www2.research.att.com/~bs/C++0xFAQ.html)中,Stroustrup似乎完全随意地使用`typename`和`class`。可能没有办法避免这种“混淆”,因为迟早你会碰到使用`class`的代码(在通常冗长的模板代码中只是少打几个字而已),而你必须知道它们其实没有区别。 - UncleBens

4
你可以使用结构体来实例化模板;然而,声明模板类型的语法只允许在你尝试使用关键字“struct”的地方出现关键字“class”或“typename”。我应该补充一点,如果你想基于编译时常量或具有外部链接的对象来实例化模板,也可以使用特定类型(例如int)...但这有点离题。

4
简短的回答是:即使是一个union或double,template 也可以接受,但不能代替class。然而,typename可以。这只是语法定义的方式。
稍微长一点的答案:在为C ++编写模板时,“发明”了一个关键字,需要在那个位置说下一个标识符将是类型名称。决定重新使用现有的class关键字。这有点令人困惑,但是普遍不愿意引入更多关键字,因为它们总是会破坏某些现有代码,当它不是关键字时,使用它作为标识符。
后来,typename因其他原因成为关键字,由于它更加适合,因此现在可以在那个位置使用它:template 。但是,有数十亿行代码使用class在那个位置,它必须保持有效。所以现在两者都允许使用。
正如在C++中常见的那样,这创造了几个阵营,以确定在那个位置使用哪个关键字。有些人坚持使用class,因为他们已经使用它超过十年。其他人喜欢typename,因为它更加适合。当期望Foo是class类型(访问成员)时,有些人使用class,而当可以使用内置时,使用typename。

3

模板参数的关键字为classtypename。这并不限制Foo参数必须是类 - 它可以是任何类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接