__uuidof在gcc中的实现

在Windows的COM模块,或者相关的代码如果想要移植到Linux上,往往会碰到很多问题,最常见的是__uuidof在gcc上不是内生支持,但是在VC上是基本的operator,相信这个问题也有不少人碰到,并且为此头痛的,下面介绍一种如果利用C++11/14的通用方法解决此问题。
(我同时也发表了这篇文章在stackoverflow:
https://stackoverflow.com/questions/43785925/deduce-template-parameter-type-name-and-generate-conjuct-variable/46173162#46173162)


先上代码:

#include <iostream>
#include <memory.h>
#include <assert.h>

using namespace std;

#define nybble_from_hex(c)      ((c>='0'&&c<='9')?(c-'0'):((c>='a'&&c<='f')?(c-'a' + 10):((c>='A'&&c<='F')?(c-'A' + 10):0)))
#define byte_from_hex(c1, c2)   ((nybble_from_hex(c1)<<4)|nybble_from_hex(c2))

typedef struct _GUID {
    unsigned long  Data1;
    unsigned short Data2;
    unsigned short Data3;
    unsigned char  Data4[ 8 ];
} GUID;

static GUID GUID_NULL = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0 ,0}};

#ifndef _REFGUID_DEFINED
#define _REFGUID_DEFINED
#ifdef __cplusplus
#define REFGUID const GUID &
#else
#define REFGUID const GUID * __MIDL_CONST
#endif
#endif

__inline int IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
{
    return !memcmp(&rguid1, &rguid2, sizeof(GUID));
}

#ifdef __cplusplus
__inline bool operator==(REFGUID guidOne, REFGUID guidOther)
{
    return !!IsEqualGUID(guidOne,guidOther);
}

__inline bool operator!=(REFGUID guidOne, REFGUID guidOther)
{
    return !(guidOne == guidOther);
}
#endif

struct Initializable : public GUID
{
    explicit
        Initializable(char const (&spec)[37])
        : GUID()
    {
        for (int i = 0; i < 8; ++i)
        {
            Data1 = (Data1 << 4) | nybble_from_hex(spec[i]);
        }
        assert(spec[8] == '-');
        for (int i = 9; i < 13; ++i)
        {
            Data2 = (Data2 << 4) | nybble_from_hex(spec[i]);
        }
        assert(spec[13] == '-');
        for (int i = 14; i < 18; ++i)
        {
            Data3 = (Data3 << 4) | nybble_from_hex(spec[i]);
        }
        assert(spec[18] == '-');
        for (int i = 19; i < 23; i += 2)
        {
            Data4[(i - 19) / 2] = (nybble_from_hex(spec[i])<<4) | nybble_from_hex(spec[i+1]);
        }
        assert(spec[23] == '-');
        for (int i = 24; i < 36; i += 2)
        {
            Data4[2 + (i - 24) / 2] = (nybble_from_hex(spec[i]) << 4) | nybble_from_hex(spec[i + 1]);
        }
    }
};

template<class T>
inline
auto __my_uuidof()
-> GUID const &
{
    return GUID_NULL;
}

#define CPPX_GNUC_UUID_FOR( name, spec )            \
template<>                                          \
inline                                              \
auto __my_uuidof<name>()                            \
    -> GUID const&                                  \
{                                                   \
    using ::operator"" _uuid;                       \
    static GUID the_uuid = spec ## _uuid;           \
                                                    \
    return the_uuid;                                \
}                                                   \
                                                    \
template<>                                          \
inline                                              \
auto __my_uuidof<name*>()                           \
    -> GUID const&                                  \
{ return __my_uuidof<name>(); }                     \
                                                    \
static_assert( true, "" )

auto operator"" _uuid(char const* const s, size_t const size) 
-> GUID
{
    return Initializable(reinterpret_cast<char const (&)[37]>(*s));
}

#define CPPX_UUID_FOR    CPPX_GNUC_UUID_FOR

#define __uuid(T)       __my_uuidof<T>()

struct Foo {};
CPPX_UUID_FOR(Foo, "dbe41a75-d5da-402a-aff7-cd347877ec00");

Foo foo;

template <class T>
void QueryInterface(T** p)
{
    if (p == NULL)
        return;

    GUID guid = "dbe41a75-d5da-402a-aff7-cd347877ec00"_uuid;
    if (__uuid(T) == guid)
    {
        *p = &foo;
    }
    else
    {
        *p = NULL;
    }

    return;
}

int main()
{
    Foo* p = NULL;
    QueryInterface(&p);

    cout << "p: " << p << ", &foo: " << &foo << endl;   

    return 0;
}

保存为uuidtest.cpp,编译并且运行它:

g++-7 uuidtest.cpp -o uuidtest
./uuidtest
p: 0x6021c0, &foo: 0x6021c0

代码稍微解释一下:
首先用到user defined literal:

operator"" _uuid(...)

它会吧uuid string转化成GUID

然后用到了function template specialization的feature,它可以给每个类定义一个特殊的__uuidof实现,然后定义一个宏让代码调用__uuidof(…)会走到这些特殊的__uuid的实现中去,这是代码的关键。

#define __uuid(T)       __my_uuidof<T>()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值