|
@@ -1234,10 +1234,45 @@ void PrintID()
|
|
|
但是呢,直觉对付更加复杂的问题还是没用的(也不是没用,主要是你没这个直觉了)。我们要把这个直觉,转换成合理的规则——即模板的匹配规则。
|
|
|
当然,这个匹配规则是对复杂问题用的,所以我们会到实在一眼看不出来的时候才会动用它。一开始我们只要把握:模板是从最特殊到最一般形式进行匹配就可以了。
|
|
|
|
|
|
+####2.2.4 即用即推导
|
|
|
+
|
|
|
+这一节我们将讲述模板一个非常重要的行为特点:那就是什么时候编译器会对模板进行推导,推导到什么程度。
|
|
|
+
|
|
|
+这一知识,对于理解模板的编译期行为、以及修正模板编译错误都非常重要。
|
|
|
+
|
|
|
+我们先来看一个例子:
|
|
|
+
|
|
|
+``` C++
|
|
|
+template <typename T> struct X {};
|
|
|
+
|
|
|
+template <typename T> struct Y
|
|
|
+{
|
|
|
+ typedef X<T> ReboundType; // 类型定义1
|
|
|
+ typedef typename X<T>::MemberType MemberType; // 类型定义2
|
|
|
+ typedef UnknownType MemberType3; // 类型定义3
|
|
|
+
|
|
|
+ void foo()
|
|
|
+ {
|
|
|
+ X<T> instance0;
|
|
|
+ X<T>::MemberType instance1;
|
|
|
+ WTF instance2
|
|
|
+ 大王叫我来巡山 - + &
|
|
|
+ }
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+把这段代码编译一下,类型定义3出错,其它的都没问题。不过到这里你应该会有几个问题:
|
|
|
+
|
|
|
+1. 不是`struct X<T>`的定义是空的吗?为什么在`struct Y`内的类型定义2使用了 `X<T>::MemberType` 编译器没有报错?
|
|
|
+2. 类型定义2中的`typename`是什么鬼?为什么类型定义1就不需要?
|
|
|
+3. 为什么类型定义3会导致编译错误?
|
|
|
+4. 为什么`void foo()`在MSVC下什么错误都没报?
|
|
|
+
|
|
|
|
|
|
###2.3 函数模板的重载、参数匹配、特化与部分特化
|
|
|
###2.4 技巧单元:模板与继承
|
|
|
|
|
|
+
|
|
|
## 3 拿起特化的武器,去写程序吧!
|
|
|
###3.1 利用模板特化规则实现If-Then-Else与Switch-Case
|
|
|
###3.2 特化可以有多个选择:替换失败并不是一个错误,只是一种可能
|