c++ primer笔记14

1. Specializing a Class Template

Our Queue class has a problem similar to the one in compare when used with C-style strings. In this case, the problem is in the push function. That function copies the value it’s given to create a new element in the Queue. By default, copying a C-style character string copies only the pointer, not the characters.

template<> class Queue<const char*> {
public:
// no copy control: Synthesized versions work for this class
// similarly, no need for explicit default constructor either
void push(const char*);
void pop() {real_queue.pop();}
bool empty() const {return real_queue.empty();}
// Note: return type does not match template parameter type
std::string front() {return real_queue.front();}
const std::string &front() const
{return real_queue.front();}
private:
Queue<std::string> real_queue; // forward calls to real_queue
};

It is worth noting that a specialization may define completely different members than the template itself. If a specialization fails to define a member from the template, that member may not be used on objects of the specilization type. The member definitions of the class template are not used to create the definitions for the members of an explicit specialization.

A class template specialization ought to define the same interface as the template it specializes. Doing otherwise will surprise users when they attempt to use a member that is not defined.

2. Class Specialization Definition

When a member is defined outside the class specialization, it is not preceded by the tokens template<>.

void Queue<const char*>::push(const char* val)
{
return real_queue.push(val);
}

3. Specializing Members but Not the Class

If we look a bit more deeply at our class, we can see that we can simplify our code: Rather than specializing the whole template, we can specialize just the push and pop members. We’ll specialize push to copy the character array and pop to free the memory we used for that copy:

template <>
void Queue<const char*>::push(const char *const &val)
{
// allocate a new character array and copy characters from val
char* new_item = new char[strlen(val) + 1];
strncpy(new_item, val, strlen(val) + 1);
// store pointer to newly allocated and initialized element
QueueItem<const char*> *pt = new QueueItem<const char*>(new_item);
// put item onto existing queue
if (empty())
head = tail = pt; // queue has only one element
else {
tail->next = pt; // add new element to end of queue
tail = pt;
}
}

template <>
void Queue<const char*>::pop()
{
// remember head so we can delete it
QueueItem<const char*> *p = head;
delete head->item; // delete the array allocated in push
head = head->next; // head now points to next element
delete p; // delete old head element
}

4. Specialization Declarations

Member specializations are declared just as any other function template specialization. They must start with an empty template parameter list:

// push and pop specialized for const char*
template <>
void Queue<const char*>::push(const char* const &);
template <> void Queue<const char*>::pop();

5. *** Class-Template Partial Specializations ***

If a class template has more than one template parameter, we might want to specialize some but not all of the template parameters. We can do so using a class template partial specialization:

template <class T1, class T2>
class some_template
{
public:
void print()
{
cout << "hello" << endl;
}
};

// partial specialization: fixes T2 as int and allows T1 to vary
template <class T1>
class some_template<T1, int>
{
};

As with any other class template, a partial specialization is instantiated implicitly when used in a program:

some_template<int, string> foo; // uses template
some_template<string, int> bar; // uses partial specialization

The definition of a partial specialization is completely disjointed from the definition of the generic template. The partial specialization may have a completely different set of members from the generic class template. The generic definitions for the members of a class template are never used to instantiate the members of the class template partial specialization.

Demo<double, int> d;
d.print();

// error: ‘class Demo<double, int>’ has no member namedprint