模板函数
- 可特化, 特化时template<>声明不能少
template <class T>
bool equal(const T& a, const T& b)
{
return a == b;
}
template <>
bool equal<const char*>(const char* const& a, const char* const& b)
{
return strcmp(a, b);
}
如果模板参数可以通过函数形参表推断可以省略,如上例中equal后面的<const char*>可以省略。
- 不可偏特化
- 不能有缺省模板实参
- 可以通过实参推断模板实参
如果调用时模板参数可以通过实参表推断,可以省略模板实参。
if (compare(a, b))
{
...
}
有多个模板参数时只能省略靠后的参数,而不能跳着省略,就像函数参数中的默认值一样。 可与同名普通函数和数目或类型不同的其它模板函数构成重载
模板类
- 可特化
- 可偏特化
偏特化本身也是模板类,所有可以为一堆类的一个集合进行定制。配合Traits能够为不同情况提供不同实现,也是Loki库和很多范形编程的支柱。
- 可以有缺省模板实参,在缺省值中可以使用前面已经出现过的模板参数
即使所有模板参数都提供了缺省值,也需要在类形名后加上<>,就像函数中所有参数都有缺省值也必须要有()
template <class T = int>
class Foo {};
Foo<>* a = new Foo<>();
- 没办法模板推断,准确的说不能通过构造函数进行模板参数推断
template <class T>
class Foo
{
Foo(const T&) {}
};
..
int n = 10.
Foo<int>* i = new Foo<int>(n);
...
成员限定符
- 如果在操作符".", "->"和"::"后出现的名称带有显式的模板实参列表时,需要加限定符template,否则模板参数列表的<会被认为是小于操作符。 (例子出自IBM)
#include <iostream>
using namespace std;
class X {
public:
template <int j> struct S {
void h() {
cout << "member template's member function: " << j << endl;
}
};
template <int i> void f() {
cout << "Primary: " << i << endl;
}
};
template<> void X::f<20>() {
cout << "Specialized, non-type argument = 20" << endl;
}
template<class T> void g(T* p) {
p->template f<100>();
p->template f<20>();
typename T::template S<40> s; // use of scope operator on a member template
s.h();
}
int main()
{
X temp;
g(&temp);
}
template template
在模板形参表中嵌套使用template可以使用模板类做为模板参数,好处是指定模板实参时只需要给出模板类的名称(不需要模板实参列表)。这种技术广泛地运用在loki库中,参考Modern C++ 的 1.5.1 Implementing Policy Classes with Template Template Parameterstemplate <class T> struct OpNewCreator
{
static T* Create()
{
return new T;
}
};
template <template <class Created> class CreationPolicy>
class WidgetManager : public CreationPolicy<Widget>
{
...
};
typedef WidgetManager<OpNewCreator> MyWidgetMgr; //不需要为OpNewCreator提供实参进行实例化了
模板函数和模板类名字查找
参考这里。
最容易碰到的问题是使用父类中的成员时需要显示加this->或者Base<T>::使得名字变得模板参数相关。