2 minute read

整理自:Thinking in C++, Volume 2


A template definition is, by its very nature, a generalization, because it describes a family of entities in general terms. When template arguments are supplied, the result is a specialization of the template because it determines a unique instance out of the many possible instances of the family of entities.

When you supply the type for the template parameter, whether explicitly or implicitly via argument deduction, the resultant code generated by the compiler (for example, min<int>()) is a specialization of the template. The code generated is also considered an instantiation of the template, as are all code bodies generated by the template facility.

Explicit specialization

You (as a template provider, instead of a template user) can also provide the code yourself for a given template specialization, should the need arise. E.g.:

#include <cstring>
#include <iostream>
using std::strcmp;
using std::cout;
using std::endl;
 
template<class T> 
const T& min(const T& a, const T& b) {
    return (a < b) ? a : b;
}
 
// An explicit specialization of the min template
template<>
const char* const& min<const char*>(const char* const& a,
                                    const char* const& b) {
    cout << "const char* specialization called" << endl;
    return (strcmp(a, b) < 0) ? a : b;
}
 
int main() {
    const char *s2 = "say \"Ni-!\"", *s1 = "knights who";
    cout << min(s1, s2) << endl;
    cout << min<>(s1, s2) << endl;
}
 
// output: 
/*
    const char* specialization called
    knights who
    const char* specialization called
    knights who
*/

The template<> prefix tells the compiler that what follows is a specialization of a template.

Note that we carefully substitute const char* for T, and we must write const char* const in place of const T in the explicit specialization.

Explicit specializations tend to be more useful for class templates than for function templates. When you provide a full specialization for a class template, though, you may need to implement all the member functions. This is because you are providing a separate class, and client code may expect the complete interface to be implemented.

template<class T, class Allocator = allocator<T>>
class vector {...};

// An explicit specialization for bool
template<> 
class vector<bool, allocator<bool>> {...};

Partial specialization

Class templates can also be partially specialized (However, we cannot partially specialize a function template.), meaning that at least one of the template parameters is left “open” in some way in the specialization. 比如上面的 template<class T, class Allocator = allocator<T>>,我们可以指定 Tbool,但是 Allocator 可以留着不指定。

template<class T, class Allocator = allocator<T>>
class vector {...};

template<class Allocator> 
class vector<bool, Allocator> {...};

这样只要是 vector<bool, Whatever> 都会落到上面的这个实现上。

但是 “is left ‘open’ in some way” 并不是只有 “留着不指定” 这么一种形式。partial template specialization 上举得例子还有:

// primary template
template<class T1, class T2, int I>
class A {};					
 
// partial specialization where T2 is a pointer to T1
template<class T, int I>
class A<T, T*, I> {};

// partial specialization where T1 is a pointer
template<class T1, class T2, int I>
class A<T1*, T2, I> {};

// partial specialization where T1 is int, I is 5, and T2 is a pointer
template<class T>
class A<int, T*, 5> {};	

具体的规则见上面的链接。反正 partial specialization 的原则就是:You must specialize something, but not all.

Tags:

Categories:

Updated:

Comments