Partilhar via


Using template specialization in C++

We all know that C++ templates can be used to write generic code, e.g.

 

template <typename T>

class Array { … };

 

Then we can use the same template to generate code for different template parameters.  This is called instantiation of the template.  e.g.

 

Array<int> x;

Array<string> y;

 

However, sometimes we don't want to use the same definition for certain template parameters.  For example, the generic definition for Array<bool> might not be as efficient as we want.  We can write a specialized implementation for Array<bool> that uses only 1 bit for each element in the array.  Such is called specialization of the template.

 

C++ supports specialization by the following syntax:

 

template <> // empty template parameter list!

class Array<bool> { … };

 

Here's the complete example.  In this program, we present a generic definition for a template class Array, then we present a specialized definition for the case when the template parameter is bool.

 

// This example shows how to supply a specialized implementation when

// instantiating C++ template class.

// This code is SIMPLIFIED for illustration purpose, and should NOT be used

// unmodified in production code!!!

// (c) Zhanyong Wan

// 3/17/2004

#include <iostream>

// The generic definition for the Array template class.

template <typename T>

class Array

{

private:

    T * elements;

    int size;

public:

    Array( int aSize )

        : size( aSize )

    {

        // size validity checking code omitted...

        elements = new T[ aSize ];

        // (elements != NULL) test omitted...

    }

    virtual ~Array()

    {

        delete[] elements;

    }

    void Set( int idx, const T& value )

    {

        // array-bound checking code omitted...

        elements[ idx ] = value;

    }

    T& Get( int idx ) const

    {

        // array-bound checking code omitted...

        return elements[ idx ];

    }

};

typedef unsigned char byte;

// An specialized implementation for Array< bool > that optimizes for space

// by representing a bool element with a single bit.

// In C++, a template with an empty parameter list is the syntax for

// specialization. IMHO, keyword overloading is abused in C++.

template <>

class Array< bool >

{

private:

    byte * buffer;

    int size;

    const static int BitsPerByte = 8;

public:

    Array( int aSize )

    {

        // size validity checking code omitted...

        buffer = new byte[ aSize/BitsPerByte + 1 ];

        // (buffer != NULL) test omitted...

    }

    virtual ~Array()

    {

        delete[] buffer;

    }

    // The specialized class is NOT obliged to have the same set of methods

    // as the generic class!

    void Set( int idx, bool value )

    // Note that we change the prototype of the Set() method here for better

    // performance. As a result, it does not match the prototype of the

    // Set() method in the template Array class. This is OK, as C++ doesn't

    // impose any relationship between a template class and its specialization.

    {

   // array-bound checking code omitted...

        const int byteIdx = idx/BitsPerByte;

        const int bitIdx = idx - byteIdx*BitsPerByte;

        const byte bitMask = 1 << bitIdx;

        if ( value )

        {

            buffer[ byteIdx ] |= bitMask;

        }

        else

        {

            buffer[ byteIdx ] &= ~bitMask;

        }

    }

    bool Get( int idx ) const

    {

        // array-bound checking code omitted...

        const int byteIdx = idx/BitsPerByte;

        const int bitIdx = idx - byteIdx*BitsPerByte;

        const byte bitMask = 1 << bitIdx;

        return ( buffer[ byteIdx ] & bitMask ) != 0;

    }

};

int main()

{

    const int size = 6;

    Array< int > intArray ( size );

    Array< bool > boolArray( size );

    for ( int i = 0; i < size; i++ )

    {

        intArray.Set( i, i );

        boolArray.Set( i, (i % 2) == 1 );

    }

    for ( i = 0; i < size; i++ )

    {

        std::cout << intArray.Get( i )

             << "\t"

             << boolArray.Get( i )

             << "\r\n";

    }

   

    return 0;

}