posts - 297,  comments - 15,  trackbacks - 0
出处 http://www.cppblog.com/cexer/archive/2008/07/05/55419.html

世界上有个叫__uuidof的关键字。这是一个家喻户晓且其被广泛使用的关键字,几乎可以说,有COM程序员的地方,就有它 __uuidof的存在。其很好很强大的程度是人所共见的,夸张一点比喻:离开它的COM程序员,就像失去了点火器的火箭,虽然可以人工点火,但是不安全 且无效率。

  不过很多人并不知道,这其实是一个编译器扩展关键字,提供了此关键字的仅VC一家别无它店。幸运的是,强大的C++让我们能够轻易仿真出这个关键字的大部分功能。

  网上能够找到一种仿真的方法,见许式伟:《仿真VC++提供的关键字__uuidof》。该方法的实现是:特化模板类的成员函数,然后运行时调用函数根据UUID字符串产生出UUID,由于是生成于运行时,所以它无可避免地有两个缺点:

  • 存在运行时消耗。
  • 无法作为非类型模板参数传递给模板。

  那些整天流着口水追求效率的C++程序员们,是不能忍受任何不必要的运行时消耗的。对于第二点,VC的关键字__uuidof取出来的UUID 是能够作为非类型模板参数传递的,ATL中就大量地使用了这样的参数传递形式,所以目前的这种实现功能有限,仿真度还不够高。

  其实只要能让它能够编译期决定UUID的值,那么这两个问题就迎刃而解了。而这是肯定可以实现的,并且很简单。我曾经在自己写的一个COM库里实现过这样的方法,虽然那个库已经不知丢到哪里去了,不过那个方法还记得。

  解决的途径还是离不开模板特化。类的成员包括成员函数和成员变量,函数是运行时作用的,然而static const的成员变量可以是编译期就决定。所以解决的方法就在眼前了:特化模板的成员变量。

  以下是我的实现方法。

  先定义一个类模板,它有一个static const ,UUID类型的成员变量:

    template<typename T>   
struct _uuid_of_impl
{
static const UUID id;
};
template<typename T>
const UUID _uuid_of_impl<T>::id=GUID_NULL;

  有了这个简单的东西就好办了,只需要针对某个接口特它的成员变量就行了,如:

    template<>    
const UUID _uuid_of_impl<IUnknown>::id=IID_IUnknown;

template<>
const UUID _uuid_of_impl<IDispatch>::id=IID_IDispatch;


  然后我们就可以这样取得接口的UUID:

    IID IunknownID=_uuid_of_impl<IUnknown>::id;   
IID IdispatchID=_uuid_of_impl<IDispatch>::id;


  作为非类型模板参数传递:

    template<const IID* t_iid>   
struct __uuid_of_test
{
__uuid_of_test()
{}

void test()
{
t_iid;
}
};

__uuid_of_test<&(_uuid_of_impl<IDispatch>::id) > obj;


  不过现在这种实现还有一些问题,看以下代码:

    IID ITypelibID=_uuid_of_impl<ITypeLib>::id;


  注意我们并没有事先对模板__uuid_of_impl特化ITypeLib的版本。但是以上语句却能够编译通过,在运行时, __uuid_of_impl<ITypeLib>的值将会是错误的值GUID_NULL。这是因为,我们定义模板的时候,同时在模板外定义 了模板的静态成员变量并赋值为GUID_NULL,所以没有用特化的方法定义UUID的接口,都将使用GUID_NULL这个通用值。这当然不是我们想要 的。所以我们想在没有定义UUID的时候让编译器警告我们,要达到这样的效果只需要去掉上面那句:

    template<typename T>   
const UUID _uuid_of_impl<T>::id=GUID_NULL;


  现在再进行编译,编译器会告诉你,有一个无法解析的符号。根据编译器提供的相关信息,很容易就能确定问题所在。这样能够在编译期极大地减小安全隐患。

  最后加上我们定义的几个宏,这是最后的全部实现:

    template<typename T>   
struct _uuid_of_impl
{
static const UUID id;
};

#define uuid_of(x) _uuid_of_impl<x>::id
#define DEFINE_UUID(x,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
template<> \
const UUID _uuid_of_impl<x>::id={l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}


  用以下代码测试通过:

    struct ITest{};   

DEFINE_UUID(ITest,0x96289151,0xf059,0x4049,0x88,0x19,0x61,0xa6,0xe9,0x79,0xc,0xf1);

template<const IID* t_iid>
struct uuid_of_test
{
uuid_of_test(){}
};

int main()
{
IID xxxxID=uuid_of(ITest);
uuid_of_test<&(uuid_of(ITest))> obj;

return 0;
}


  需要注意的是DEFINE_UUID应该在实现文件(*.cpp,*.cxx,……)当中使用。到这里,仍有一些使用方法与VC的关键 字是不一样的,所以仍没做到仿真度100%。不过我相信通过预处理元编程,能够相当程度地逼近它,只是我对预处理元编程不是很了解,所以就不在这里献丑 了。

posted on 2008-07-19 14:03 chatler 阅读(819) 评论(0)  编辑 收藏 引用 所属分类: VC_MFC

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


<2008年7月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

常用链接

留言簿(10)

随笔分类(307)

随笔档案(297)

algorithm

Books_Free_Online

C++

database

Linux

Linux shell

linux socket

misce

  • cloudward
  • 感觉这个博客还是不错,虽然做的东西和我不大相关,觉得看看还是有好处的

network

OSS

  • Google Android
  • Android is a software stack for mobile devices that includes an operating system, middleware and key applications. This early look at the Android SDK provides the tools and APIs necessary to begin developing applications on the Android platform using the Java programming language.
  • os161 file list

overall

搜索

  •  

最新评论

阅读排行榜

评论排行榜