2.5 Specializations of Class Templates
2.5 类模板的特化
You can specialize a class template for certain template arguments. Similar to the overloading of function templates (see Section 1.5 on page 15), specializing class templates allows you to optimize implementations for certain types or to fix a misbehavior of certain types for an instantiation of the class template. However, if you specialize a class template, you must also specialize all member functions.
你可以用模板实参来特化类模板,和函数模板的重载类似(见第15页1.5节)。你可以优化基于某种特定类型的实现,或者修复某种特定类型在实例化类模板时所出现的不足。但是,当你特化类模板时,必须同时特化所有的成员函数。
Although it is possible to specialize a single member function of a class template, once you have done so, you can no longer specialize the whole class template instance that the specialized member belongs to.
虽然可以只特化某个成员函数,但这个做法并没有特化整个类,也就没有特化整个类模板。
To specialize a class template, you have to declare the class with a leading template<> and a specification of the types for which the class template is specialized. The types are used as a template argument and must be specified directly following the name of the class:
为了特化一个类模板,你必须在起始处声明一个template<>,接下来声明用来特化类模板的类型。这个类型被作用模板实参,且必须在类名的后面直接指定。
template<> class Stack<std::string> { … };
For these specializations, any definition of a member function must be defined as an “ordinary” member function, with each occurrence of T being replaced by the specialized type:
进行类模板的特化时,每个成员函数都必须重新定义为普通函数,原来模板函数中的每个T也相应地被进行特化的类型取代:
void Stack<std::string>::push (std::string const& elem) { elems.push_back(elem); // append copy of passed elem }
Here is a complete example of a specialization of Stack<> for type std::string:
下面是一个用std::string特化Stack<>的完整例子:
#include "stack1.hpp" #include <deque> #include <string> #include <cassert> template<> class Stack<std::string> { private: std::deque<std::string> elems; // elements public: void push(std::string const&); // push element void pop(); // pop element std::string const& top() const; // return top element bool empty() const { // return whether the stack is empty return elems.empty(); } }; void Stack<std::string>::push (std::string const& elem) { elems.push_back(elem); // append copy of passed elem } void Stack<std::string>::pop () { assert(!elems.empty()); elems.pop_back(); // remove last element } std::string const& Stack<std::string>::top () const { assert(!elems.empty()); return elems.back(); // return copy of last element }
In this example, the specialization uses reference semantics to pass the string argument to push(), which makes more sense for this specific type (we should even better pass a forwarding reference, though, which is discussed in Section 6.1 on page 91).
在这个例子里,特化使用引用语义传递将string参数给push()函数,这对这种类型更加有意义(不过,我们最好使用完美转发,这将在第91页的6.1节中进行讨论)
Another difference is to use a deque instead of a vector to manage the elements inside the stack. Although this has no particular benefit here, it does demonstrate that the implementation of a specialization might look very different from the implementation of the primary template.
另一处不同就是使用了deque而不是vector来管理stack内部的元素。我们使用这种用法并不在于获得某种好处,而只是为了说明:特化的实现可以和基本类模板(primary template)的实现完全不同(译注:事实上,使用deque代替vector来实现一个stack是有好处的。因为当删除元素时,deque会释放内存;当需要重新分配内存时,deque的元素并不需要被移动。正是这个原因,C++标准库中的stack<>就是使用deque来作为容器类。但是这种好处对于string不起作用)