HOWTO: Work Around Bugs in Template Libraries

ID: Q182046


The information in this article applies to:
  • Microsoft Visual C++, 32-bit Editions, versions 5.0, 6.0


SUMMARY

Occasionally, bugs are found in a template library. Because all the source code for the library is available, it is tempting to go into the source code and modify the library. This is not advisable because there may be unintended side effects from the modifications to the library. In addition, technical support staff from the library vendor may decline to support a modified library.

This article describes the following methods to work around bugs in template libraries without modifying the library, by using features of the C++ language:

  • Specialize the template function that has the bug.


  • Specialize the template class member that has the bug.


  • Specialize the template class that has the bug.


  • Derive from the template class to extend its functionality.


  • Use a #define/#undef pair around a #include to change a symbol name in a template header that may be causing a conflict.



MORE INFORMATION

Below are several descriptions of how to work around bugs in a template library. One or more of these workarounds may be applicable in any given case.

The first three methods discuss specializing a template. To discover all of the specializations required, compile without optimizations (to prevent inlining any of these functions). Then either use DUMPBIN /SYMBOLS or use the /MAP linker option to generate a map file. In either case, you can find all of the specializations of the template class, function, or member used in the application. You need to provide a separate template specialization for each of these.

Method 1. Specialize the template function that has the bug.

To work around a bug in the template function CopyElements in AfxTempl.h that causes a series of elements to be incorrectly copied, you can specialize CopyElements for each type used in your program. The template declaration in AfxTempl.h is:

template<class TYPE> inline void AFXAPI
   CopyElements(TYPE* pDest, const TYPE* pSrc, int nCount)
   {
   ...
   } 
Supply a specialization for each object type that is used in CopyElements. For example, suppose you use CopyElements for an array of class MyType. Then your specialization would look similar to the following:

template<>
   inline void AFXAPI
   CopyElements<MyType>(MyType* pDest, const MyType* pSrc, int nCount)
   {
   // You supply the code to copy the elements.
   } 

Method 2. Specialize the template class member that has the bug.

To work around a bug in the template class member function deque<T>::_Buyback(), you can specialize this member function for each type of deque in your program. For instance, if you used a deque<MyType> in your program, you can specialize _Buyback() as follows:

template<>
   void std::deque<MyType>::_Buyback()
   {
   // You supply the code.
   } 

Method 3. Specialize the template class that has the bug.

It is usually simpler to specialize class members that contain bugs. However, there are some circumstances when the whole class must be specialized. For instance, Visual C++ 5.0 doesn't support partial template specialization. This means that class iterator_traits<T*> does not exist, which means you can't use iterator_traits with a pointer type. In this case, you can specialize iterator_traits for each of the pointer types in your program:

namespace std {


       template<>
       struct iterator_traits<MyType*> {
           typedef ptrdiff_t difference_type;
           typedef MyType value_type;
           typedef MyType* pointer;
           typedef MyType& reference;
           typedef random_access_iterator_tag iterator_category;
       };

   } 

Method 4. Derive from the template class to extend its functionality.

Suppose that you need class CComPtr (defined in Atlbase.h) to have additional members const operator ->>() const and operator const T*() const. To accomplish this, create a template class and derive from it, and provide the additional member functions you need:

template <class T>
   class CMyComPtr : public CComPtr<T>
   {
   public:


       operator const T*() const {return (const T*)p;}
       const T* operator->() const {_ASSERTE(p!=NULL);return (const T*)p;}

       // You supply the other required member functions.
   }; 
Your derived class should mimic the behavior of the base class as closely as possible, with the exception of the added members, to extend the functionality of the base class. The derived class does not need to supply an implementation of every member of the base class. But pay careful attention to construction and copy (assignment operators and copy constructors) so that your derived class can be used in the same ways as the base class.

Method 5. Use a #define/#undef pair around a #include to change a symbol name in a template header that may be causing a conflict.

For instance, suppose you had a source file MyProg.cpp:

   #include <vector>
   class MyTest {
   public:
       int _Ty;
       bool operator < (const MyTest&) const;
       bool operator == (const MyTest&) const;
   };
   int main ()
   {
       std::vector<MyTest> a;
       return 1;
   } 
This results in the following:

error C2300: 'MyTest' : class does not have a destructor called '~Ty'
This is clearly a bug. The cause of the bug is that the template parameter "class _Ty" in one of the STL headers conflicts with the data member named "_Ty" in class MyTest. To work around the problem, you need to change one of the symbols--either "class _Ty" or "int _Ty". Renaming "int _Ty" in MyTest is the preferred way to work around this problem. If this is not possible, as a last resort you can change the template parameter "class _Ty" to "class _Ty0" without modifying the STL library. This can be done by surrounding the include directive for the vector header with #define/#undef directives as follows:

   #define _Ty _Ty0
   #include <vector>
   #undef _Ty 

Additional query words: STL ATL afxtempl.h

Keywords : kbATL kbCompiler kbCPPonly kbMFC kbVC kbVC500 kbVC600 STLIss
Version : winnt:5.0,6.0
Platform : winnt
Issue type : kbhowto


Last Reviewed: July 20, 1999
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.