全部博文(149)
分类: C/C++
2005-12-31 10:51:02
| ||||
本文运行环境:VC6 SP5, NT4 SP3, Windows 98, Windows 2000 www.cuj.com上有一篇十分有意思关于基于模板技术编程的文章。它用一个简单的struct来实现将哑元转换值转化为可识别类型: template struct Int2Type { enum { value = v }; }; 文章主要是介绍类,但也指出了为什么模板函数在VC众特别有用。Visual C++ 6.0编译器中存在一个编号为Q240871的bug,在MSDN中的介绍如下: 症状 如果所有的模板参数在函数参数或返回类型中都没有被使用,那么重载的模板函数将不正确。 原因 这个bug是由于编译器修饰模板函数的名字造成的。名字修饰使用参数和返回类型来进行,而并不明确指出模板参数类型。于是,所有这样的模板函数将得到同样的修饰名字<…> 解决 在函数中使用哑参数。 另一篇比较有趣的技术文章是。模板并不处理对象集成,但哑参数则能够在特殊的类模板和它们的子类重实现。我们来举一个应用这些原则实现的指针验证程序的例子。 MFC拥有两个验证宏;ASSERT_VALID用于基于CObject的类,而ASSERT_POINTER用于其他类。我们来介绍一个单一模板函数来取代这二者。由于整个东西都完全可以运行,因此我们省略一些不必要的细节来节省篇幅。ASSERT_VALID宏调用AfxAssertValidObject()。在其他对象中,他检查对象的虚表(virtual table)指针。为了做到这一点,我们首先必须检查类是否拥有它。下面的附加struct可以帮助我们: template { class X : public T { X(); virtual void dummy(); }; enum { has_table = sizeof(X) == sizeof(T) }; }; 然后,我们引入一个AssertVTable模板函数,包括“真正的”和它的特殊的void“伪”Int2Type模板参数: template { ASSERT(AfxIsValidAddress(*(void**)pData, sizeof(void*), FALSE)); } inline void AssertVTable(const void*, Int2Type<0>) {} 下面是公共的验证程序,在参数表后面包括省略号: template { ASSERT(AfxIsValidAddress(pData, sizeof(T))); AssertVTable(pData, Int2Type } 下面的验证程序针对CObject子类替代上面的那个: template const CObject*) { ASSERT(AfxIsValidAddress(pOb, sizeof(T))); ASSERT(AfxIsValidAddress(*(void**)pOb, sizeof(void*), FALSE)); pOb->AssertValid(); } 当然,也可以用同样的方式针对其他类的继承类加入验证程序。 下面是应用程序中使用的顶级函数: template { AssertValidPointer(pData, pData); } template { if(NULL != pData) AssertValidPointer(pData, pData); } 把上面的东西放到#if/#else/#endif块中,以便在发行版(release build)中禁用它们: #ifdef _DEBUG ... #else //_DEBUG #define CHECK_ADDRESS(pData) ((void)0) #define CHECK_NULL_OR_ADDRESS(pData) ((void)0) #endif //!_DEBUG 现在我们就可以使用CHECK_ADDRESS()和CHECK_NULL_OR_ADDRESS()了。 在文章的最后,我斗胆提议使用一个独特的方法来用模板模拟枚举(enums)。这样写只是为了好玩,不过它确实能在无法将枚举项不能放到一起的时候帮助我们: #include #define ENUM(val) template<> struct cnt<__LINE__> { enum {v = cnt<__LINE__-1>::v+1}; }; enum { val = cnt<__LINE__>::v }; template<> struct flg namespace test { template template template<> struct cnt<__LINE__> { enum {v = -1 }; };
// 在这里放一点东西 ENUM(b) // 在这里放一点东西 ENUM(c)
{ enum { u = bnd<(i+1) | flg::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 << " "; return 0; } |