FAQ 25.03 How can a template class be specialized to handle special cases?

Use explicit specialization.

Sometimes a programmer wants the compiler to bypass the class template when creating an instantiation of a class template for a particular type and use a specialized class template instead. For example, suppose that an array of bits is needed. The natural thing to do is create an Array<bool> using the template class from FAQ 25.02.

 #include "Array.hpp" int main() {   Array<bool> ab;   ab[5] = true; } 

If the previously defined Array template were used to generate the code for this class, it would end up creating an array of bool which would, at best, be optimized to be an array of bytes. Clearly a bit array would be more space-efficient than a byte array. This more space-efficient implementation can be created by defining class Array<bool> as an explicit specialization of the class template Array. Notice how class Array<bool> uses a bit array rather than a byte array.

 #include <new> using namespace std; template<class T> class Array; template<> class Array<bool> { public:   typedef  unsigned char  Byte;   class BitRef {   public:     BitRef(Byte& byte, unsigned bit) throw();     operator bool() throw();     BitRef& operator= (bool b) throw();   private:     Byte& byte_;     unsigned bit_;   };   Array(unsigned size=10) throw(bad_alloc);   Array(const Array<bool>& a) throw(bad_alloc);   Array<bool>& operator= (const Array<bool>& a) throw(bad_alloc);   ~Array() throw();   unsigned size() const throw();   bool   operator[] (unsigned i) const throw();   BitRef operator[] (unsigned i)       throw(); protected:   unsigned size_;   Byte*    arr_; }; template<> inline Array<bool>::Array(unsigned size) throw(bad_alloc) : size_(size) , arr_ (new Byte[(size+7u)/8u]) { memset(arr_, '\0', (size+7u)/8u); } template<> inline Array<bool>::~Array() throw() { delete[] arr_; } template<> inline unsigned Array<bool>::size() const throw() { return size_; } template<> inline bool Array<bool>::operator[] (unsigned i) const throw() { return (arr_[i/8u] >> (i&7u)) & 1u; } template<> inline Array<bool>::BitRef Array<bool>::operator[] (unsigned i) throw() { return BitRef(arr_[i/8u], i&7u); } template<> inline Array<bool>::BitRef::BitRef(Byte& byte, unsigned bit) throw() : byte_(byte) , bit_(bit) { } template<> inline Array<bool>::BitRef::operator bool() throw() { return (byte_ >> bit_) & 1u; } template<> inline Array<bool>::BitRef& Array<bool>::BitRef::operator= (bool b) throw() {   if (b) byte_ |=  (1u << bit_);   else   byte_ &= ~(1u << bit_);   return *this; } 

Array<bool> is an explicit specialization of the class template Array, and Array<bool> will be used instead of Array whenever an Array<bool> is needed.

 int main() {   Array<int>   ai;  ai[5] = 42;                      <-- 1   Array<float> af;  af[5] = 42.0;                    <-- 2   Array<char>  ac;  ac[5] = 'x';                     <-- 3   Array<bool>  ab;  ab[5] = true;                    <-- 4 } 

(1) Uses the generic class template

(2) Uses the generic class template

(3) Uses the generic class template

(4) Uses explicit specialization, not the generic class template

Explicit specializations are often used to take advantage of special properties of the type T and achieve space and/or speed benefits that could not be achieved using the generic class template.

It is normally best to define the explicit specialization (for example, Array<bool>) in the same header that defines the template itself (for example, the same header that defines Array<T>). That way the compiler is guaranteed to see the explicit specialization before any uses of the specialization occur.



C++ FAQs
C Programming FAQs: Frequently Asked Questions
ISBN: 0201845199
EAN: 2147483647
Year: 2005
Pages: 566
Authors: Steve Summit

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net