一 、“函数模板”与“模板函数”
下面几行代码就是一个“函数模板”
template <class T>
T abs(T x)
{
return x < 0 ? -x : x;
}
根据“函数模板”可以生成不同的函数,这些“实例化”的函数被称之为“模板函数”。
如:abs(0.1f); 编译器将根据函数模板生成模板函数abs<float> ,并调用abs<float>(0.1f)
如:abs(0.1); 编译器将根据函数模板生成模板函数abs<double>,并调用abs<double>(0.1)
二、函数模板的特例化
template <>
const char* abs<const char*>(const char*s)
{
if(s && s[0] == '-')
{
return s + 1;
}
return NULL;
}
代码 abs("-5") 将调用特化后的 abs<const char*> 函数。
三、函数模板的匹配
template <class T>
T abs(T x)
{
return x < 0 ? -x : x;
}
int abs(int x)
{
return x < 0 ? -x : x;
}
代码 abs(1) 将调用 abs,而不是模板函数 abs<int>,也就是说:非模板函数具有优先权
下面再考虑函数模板被特化后的匹配问题:增加如下代码
template <>
int abs<int>(int x)
{
return x < 0 ? -x : x;
}
同样的代码 abs(1),将调用什么呢?答案是:不确定。具体来说,对于 VC++6.0 而言,abs
函数和模板函数 abs<int> 被当做同一函数,谁先定义谁就有效。对于 VC++2008 而言,abs
函数和模板函数 abs<int> 是两个函数,但 abs 的优先级高于 abs<int>。
总结:对于VC++2008而言,始终是非模板函数具有优先权。对于VC++6.0而言,函数模板被
特化时要特别小心。
四、 类模板与特化
下面是一个类模板的例子
template <class T1,class T2>
class CTest
{
public:
T1 m_a;
T2 m_b;
};
1、全特化
template <>
class CTest<int,double>
{
public:
T1 m_a; //编译器自动将 T1 替换为 int
T2 m_b; //编译器自动将 T2 替换为 double
};
2、偏特化(VC++6.0 至 VC++2003不支持偏特化)
template <class T1>
class CTest<T1,int>
{
public:
T1 m_a;
int m_b; //这里不能再使用 T2
};
五、成员函数模板、模板成员函数、特化
class CTest
{
public:
template<class T>
T Add(T x) const
{//成员函数模板
return (T)m_a + x;
};
public:
int m_a;
};
CTest::Add 就是一个成员函数模板,编译器将根据不同的参数生成不同的模板成员函数。
下面是成员函数模板的特化:
class CTest
{
public:
template<class T>
T Add(T x) const
{
return (T)m_a + x;
};
template<>
double Add<double>(double x) const
{//这个就是特化后的成员函数
return (double)m_a + x;
};
public:
int m_a;
};
VC++6.0 不允许特化成员函数模板的声明、定义分离,如下面的代码在 VC++6.0 里无法编译
class CTest
{
public:
... ... ...
template<>
double Add<double>(double x) const; //特化函数声明
... ... ...
};
//特化函数实现
template<>
double CTest::Add<double>(double x) const;
{
return (double)m_a + x;
};