Template Mania

Environment: VC6 SP5, NT4 SP3, Windows 98, Windows 2000

There is an interesting article concerning template-based technique on www.cuj.com [1]. A simple struct is introduced there that helps to implement dummy arguments converting values to distinquishable types:

template<int v>
struct Int2Type
{
   enum { value = v };
};
The main article idea is generally described in terms of classes, but there is a reason why it can be especially useful for template functions with VC. There is a bug Q240871 in the Microsoft Visual C++ 6.0 compiler, its description from the MSDN is given below:

SYMPTOMS

If all the template parameters are not used in function arguments or return type of a template function, the template functions are not overloaded correctly.

CAUSE

The bug is the result of the way the compiler decorates template function names. Name Decoration uses the arguments and return type and doesn't use the explicitly specified template argument type. Therefore, all three template function instantiations receive the same decorated name<...>

RESOLUTION

Use dummy arguments to the function.

There is another interesting technique outlined in [2]. Templates do not deal with objects hierarchy, but dummy arguments combined with ellipses make it possible to specialize templates for classes and their subclasses. Let us implement a pointer validity checking utility based on these principles as an example.

MFC has two validating macros: ASSERT_VALID for CObject-based classes and ASSERT_POINTER for others. We introduce a single template function that supersedes both of them. The whole stuff being workable, some details will be omitted for simplicity. ASSERT_VALID macro invokes AfxAssertValidObject(). Among other things, it checks the object virtual table pointer. To do so, we need to find out if the class has one first. The next accessory struct can help us:

template<class T> struct HasVirtualTable
{
   class X : public T
   {
      X();
      virtual void dummy();
   };
   enum { has_table = sizeof(X) == sizeof(T) };
};
Then we introduce an AssertVTable template function for the "TRUE" and its void specialization for the "FALSE" (0) Int2Type template parameter:
template<typename T> inline void AssertVTable(const void* pData, T)
{
  ASSERT(AfxIsValidAddress(*(void**)pData, sizeof(void*), FALSE));
}

inline void AssertVTable(const void*, Int2Type<0>) {}
Here goes the common validating routine with an ellipse at the end of the arguments list:
template<class T> inline void AssertValidPointer(const T* pData, ...)
{
  ASSERT(AfxIsValidAddress(pData, sizeof(T)));
  AssertVTable(pData, 
               Int2Type<HasVirtualTable<T>::has_table>());
}
The next validating routine substitutes the previous one for CObject subclasses:
template<class T> inline void AssertValidPointer(const T* pOb,
                                                      const CObject*)
{
  ASSERT(AfxIsValidAddress(pOb, sizeof(T)));
  ASSERT(AfxIsValidAddress(*(void**)pOb, sizeof(void*), FALSE));
  pOb->AssertValid();
}
We can add customized validating routine for any class hierarchy branch in the same way.

Here are the top level functions to be used in the application:

template<class T> inline void CHECK_ADDRESS(const T* pData)
{
  AssertValidPointer(pData, pData);
}
template<class T> inline void CHECK_NULL_OR_ADDRESS(const T* pData)
{
  if(NULL != pData)
     AssertValidPointer(pData, pData);
}
We put stuff listed above into the #if/#else/#endif brackets to disable the functionality in the release build:
#ifdef _DEBUG
   ...
#else //_DEBUG
#define CHECK_ADDRESS(pData)          ((void)0)
#define CHECK_NULL_OR_ADDRESS(pData)  ((void)0)
#endif //!_DEBUG
Now we can use the CHECK_ADDRESS() and CHECK_NULL_OR_ADDRESS() functions.

At the end of the article I would dare to propose an exotic way to simulate enums using templates. It was written for fun only, but seems to be interesting and can actually help when there is no other way to keep enum items together:

#include <iostream>

#define ENUM(val) \
template<> struct cnt<__LINE__> { enum {v = cnt<__LINE__-1>::v+1}; }; \
enum { val = cnt<__LINE__>::v };	\
template<> struct flg<val> { enum {v = 0}; };

namespace test
{
  template<int i> struct flg { enum {v = -1}; };
  template<int i> struct cnt { enum {v = cnt<i-1>::v }; };
  template<> struct cnt<__LINE__> { enum {v = -1 }; };

  ENUM(a)

// Some stuff here

  ENUM(b)

// Some stuff here

  ENUM(c)

  template<int i> struct bnd 
  {
     enum 
     {
        u = bnd<(i+1) | flg<i+1>::v>::v,
        v = (-1 == u)? i : u
     };
  };
  template<> struct bnd<-1> { enum { v = -1 }; };
  enum { upper_bound = (bnd<0>::v | flg<0>::v)+1 };
};

int main()
{
  cout << test::a << ',' 
       << test::b << ',' 
       << test::c << ',' 
       << test::upper_bound << "\n";
  return 0;
}

References

[1] Andrei Alexandrescu "Generic Programming: Mappings between Types and Values"

[2] "Template Overloading For Base Class Pointers", by Don Wong



Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: April 22, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Database professionals — whether developers or DBAs — can often save valuable time by learning to get the most from their new or existing productivity tools. Whether you're responsible for managing database projects, performing database health checks and reporting, analyzing code, or measuring software engineering metrics, it's likely you're not taking advantage of some of the lesser-known features of Toad from Dell. Attend this live …

  • The impact of a data loss event can be significant. Real-time data is essential to remaining competitive. Many companies can no longer afford to rely on a truck arriving each day to take backup tapes offsite. For most companies, a cloud backup and recovery solution will eliminate, or significantly reduce, IT resources related to the mundane task of backup and allow your resources to be redeployed to more strategic projects. The cloud - can now be comfortable for you – with 100% recovery from anywhere all …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds