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;


}

Skip to main content