2017-05-04 58 views
0

有一个在Windows平台上一些传统的COM代码,并希望移植到Linux,但__uuidof()不能在GCC推断模板参数类型名称和生成conjuct可变

适用于大多数情况下,它可以用下面的代码来解决它。

#define __uuidof(T) IID_ ##T 

但对于某些情况下,它不能正常工作,例如,

template <class T> 
HRESULT QueryInterface(IUnknown* p, T** ppv) 
{ 
    return p->QueryInterface(__uuidof(T), (void**)ppv); 
} 

所以我想实现一个模板函数让它工作,像如,

template <class T> 
GUID __uuidof() 
{ 
    return IID_ ##typeof(T); 
} 

如何实现它并让它与一般解决方案完全一致?无法保证每个接口定义中都存在静态成员_IID。

谢谢。

+0

你看过['typeid'](http://en.cppreference.com/w/cpp/language/typeid)吗? – nwp

+0

typeid可以在编译期间工作以获得像预处理指令一样的合并变量吗? –

+0

不幸的是'typeid'不会产生编译时可用值,但它仍然可以解决您在示例中显示的问题。 – nwp

回答

0

继承根据岗位How can I define an UUID for a class, and use __uuidof, in the same way for g++ and Visual C++?虽然我不能在该职位成功编译代码的所有类的工作,但这个想法是好的,继后想法在它提到的,并且其可被编译和运行以及给出一个示例代码下GCC解决__uuidof

#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,我使用的克++ - 7编译它成功(其他具有C++ 11/14支持的gcc也可以很好地工作),并且运行良好:

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

也许typeid的将工作

否则, 可以使用的reinterpret_cast。

For exemple here we have the class A; 

A * ex; 
ex = reinterpret_cast<A>(*pv); 
if (ex == NULL) 
{ 
    //Do some stuff 
    //this means **ex** isn't a A class 
} 

它会在从A.

+0

对不起,我的坏,我编辑我的帖子 – Drumz

+0

关键是如何返回从IUnknown继承的一个接口的uuid,我认为你的代码无法捕捉它。 –

+0

在我的学习期间,typeid是不允许的,在这种情况下,我曾经使用reinterpret_cast。 – Drumz