2017-05-04 121 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