更新2.2.3节。

This commit is contained in:
Ye WU 2014-03-21 00:05:40 -07:00
parent 48610a1a97
commit 6ba46efbf1

View File

@ -1037,10 +1037,40 @@ template <> class TypeToID<int const * volatile * const volatile>;
此时就很明白了,只要 `<>` 内填进去的是一个C++能解析的合法类型,模板都能让你特化。不过这个时候如果你一点都没有写错的话, `PrintID` 中只打印了我们提供了特化的类型的ID。那如果我们没有为之提供特化的类型呢比如说doubleOK实践出真知我们来尝试着运行一下 此时就很明白了,只要 `<>` 内填进去的是一个C++能解析的合法类型,模板都能让你特化。不过这个时候如果你一点都没有写错的话, `PrintID` 中只打印了我们提供了特化的类型的ID。那如果我们没有为之提供特化的类型呢比如说doubleOK实践出真知我们来尝试着运行一下
``` C++
void PrintID()
{
cout << "ID of double: " << TypeToID<double>::ID << endl;
}
``` ```
嗯,它输出的是-1。我们顺藤摸瓜会看到 `TypeToID`的类模板“原型”的ID是值就是-1。通过这个例子可以知道当模板实例化时提供的模板参数不能匹配到任何的特化形式的时候它就会去匹配类模板的“原型”形式。
不过这里有一个问题要厘清一下。和继承不同,类模板的“原型”和它的特化类在实现上是没有关系的,并不是在类模板中写了 `ID` 这个Member那所有的特化就必须要加入 `ID` 这个Member或者特化就自动有了这个成员。完全没这回事。我们把类模板改成以下形式或许能看的更清楚一点
``` C++
template <typename T> class TypeToID
{
public:
static int const NotID = -2;
};
template <> class TypeToID<float>
{
public:
static int const ID = 1;
};
void PrintID()
{
cout << "ID of float: " << TypeToID<float>::ID << endl; // Print "1"
cout << "NotID of float: " << TypeToID<float>::NotID << endl; // Error! TypeToID<float>使用的特化的类这个类的实现没有NotID这个成员。
cout << "ID of double: " << TypeToID<double>::ID << endl; // Error! TypeToID<double>是由模板类实例化出来的它只有NotID没有ID这个成员。
}
``` ```
这样就明白了。类模板和类模板的特化的作用,仅仅是指导编译器选择哪个编译,但是特化之间、特化和它原型的类模板之间,是分别独立实现的。所以如果多个特化、或者特化和对应的类模板有着类似的内容,很不好意思,你得写上若干遍了。
前面的例子里面,我们使用了单参数的模板。不过既然模板有多个参数的形式,那特化也得支持多个参数。 前面的例子里面,我们使用了单参数的模板。不过既然模板有多个参数的形式,那特化也得支持多个参数。
###2.3 函数模板的重载、参数匹配、特化与部分特化 ###2.3 函数模板的重载、参数匹配、特化与部分特化