File tree Expand file tree Collapse file tree 1 file changed +18
-1
lines changed Expand file tree Collapse file tree 1 file changed +18
-1
lines changed Original file line number Diff line number Diff line change @@ -1630,7 +1630,24 @@ template <typename T> struct Y
1630
1630
1631
1631
事实上,标准对` typename ` 的使用规定极为复杂,也算是整个模板中的难点之一。如果想了解所有的标准,需要阅读标准14.6节下2-7条,以及14.6.2.1第一条中对于` current instantiation ` 的解释。
1632
1632
1633
- 简单来说,如果编译器能在出现的时候知道它的类型,那么就不需要` typename ` ,如果必须要到实例化的时候才能知道它是不是合法,那么定义的时候就把这个名称作为变量而不是类型。
1633
+ 简单来说,如果编译器能在出现的时候知道它是一个类型,那么就不需要` typename ` ,如果必须要到实例化的时候才能知道它是不是合法,那么定义的时候就把这个名称作为变量而不是类型。
1634
+
1635
+ 我们用一行代码来说明这个问题:
1636
+
1637
+ ``` C++
1638
+ a * b;
1639
+ ```
1640
+
1641
+ 在没有模板的情况下,这个语句有两种可能的意思:如果` a ` 是一个类型,这就是定义了一个指针` b ` ,它拥有类型` a* ` ;如果` a ` 是一个对象或引用,这就是计算一个表达式` a*b ` ,虽然结果并没有保存下来。可是如果上面的` a ` 是模板参数的成员,会发生什么呢?
1642
+
1643
+ ``` C++
1644
+ template <typename T> void meow ()
1645
+ {
1646
+ T::a * b; // 这是指针定义还是表达式语句?
1647
+ }
1648
+ ```
1649
+
1650
+ 编译器对模板进行语法检查的时候,必须要知道上面那一行到底是个什么——这当然可以推迟到实例化的时候进行(比如VC,这也是上面说过VC可以不加` typename ` 的原因),不过那是另一个故事了——显然在模板定义的时候,编译器并不能妄断。因此,C++标准规定,在没有` typename ` 约束的情况下认为这里` T::a ` 不是类型,因此` T::a * b; ` 会被当作表达式语句(例如乘法);而为了告诉编译器这是一个指针的定义,我们必须在` T::a ` 之前加上` typename ` 关键字,告诉编译器` T::a ` 是一个类型,这样整个语句才能符合指针定义的语法。
1634
1651
1635
1652
在这里,我举几个例子帮助大家理解` typename ` 的用法,这几个例子已经足以涵盖日常使用[ (预览)] [ 3 ] :
1636
1653
You can’t perform that action at this time.
0 commit comments