Learning to be Giant.

【译】为什么C++同时支持Class和Typename

|

最近读代码常会看到一些之前没有遇到过或者没有仔细思索过的语言特性,其中`typename`和`class`的区别就是这其中一个。在搜索资料时候看到Stan Lippman在04年写的一篇博客挺不错的,由于没有看到中文翻译,索性就翻译一下,加深一下理解。原文传送门]。 最近有些人问我为什么C++同时支持用`class`和`typename`来表示类型参数,毕竟这两个关键字也没有和平台相关的特性。`class`并不是暗指一个原生的类型(native type),而`typename`也并不意味着其表示的就是一个CLI类型。相反地,这两个都表示其后面的这个名称是一个将会被用户定义的实际类型所替代的参数化的类型占位符。 其实,这两个关键字的存在是有历史原因的。在一开始的模板的说明中,Stroustrup(C++创始人)复用了已经有的`class`关键字来表明一个类型参数,而不是引进一个新的关键字,因为这样有可能会使得现有的程序无法工作。新的关键字并不是没有被考虑,只是人们认为考虑到它可能带来的对现有程序的干扰,新的关键字可能并不是很必要。所以直到ISO-C++标准出台,`class`都是唯一的声明类型参数的方法。 复用已有的关键字似乎总是会导致一些误解。我们发现,新手们常常会担心使用`class`是不是会将用户可以使用的参数类型限制为class类型(就是类)而不可以使用其他的内建类型或者指针类型(即,`class`这个关键字是不是表示只允许在指定真实类型的时候只允许使用类这种类型)。所以,人们感觉到没有引入一种新的关键字是一个错误。 在标准化的过程当中,人们发现在模板定义当中的一些写法虽然本应该被解析成为声明,却被解析成了表达式(语句)。比如: ```cpp template class Demonstration { public: void method() { T::A *aObj; // oops … // … }; ``` 尽管包含`aObj`的这条语句的本意是声明一个类型参数T当中的内嵌类型A的指针,语法却将其解释成了一个算术运算,表示将T的静态成员变量A与`aObj`相乘,之后将结果丢弃。这岂不是很烦!(这种困境在泛型当中是不可能的,因为没有方法能够安全的验证任何T当中都包含A,所以运行时环境可以安全的构造一个泛型的实例)*(我承认,最后这句话究竟在说什么我也没太搞清楚)*。 委员为认为一个新的关键字就是避免编译器这种执念的好方法。新的关键字就是`typename`。当运用在语句当中的时候: ```cpp typename T::A* a6; // declare pointer to T’s A ``` 它只是编译器将接下来的语句视为声明。既然有了这么一个新的关键字,我们何不就顺便用它也来解决一下之前由于复用`class`这个关键字造成的困惑呢?当然了,考虑到当时就已经有了的这些代码、书籍、文章、演讲以及招贴都已经在使用`class`这个关键字了,委员会决定还是保留对于`class`这个关键字这种用法的支持吧。这样就是为什么这两个关键字现在都在C++当中的原因。

Comments