2012-11-24 66 views
5

我想實現一個模板類(名爲Get <>在這裏),給定結構H,類型Get<H>::typeH本身如果qualified-idH::der不存在,並且是Get<H::der>::type否則。我不明白下面的代碼有什麼問題:C++遞歸型性狀

#include <iostream> 
#include <typeinfo> 
using namespace std; 

template<class U, class V = void> 
struct Get 
{ 
    static const char id = 'A'; 
    typedef U type; 
}; 

template<class U> 
struct Get<U,typename U::der> 
{ 
    static const char id = 'B'; 
    typedef typename Get<typename U::der>::type type; 
}; 

struct H1 
{ }; 
struct H2 
{ typedef double der; }; 
struct H3 
{ typedef void der; }; 
struct H4 
{ typedef H2 der; }; 

void print(char id, const char* name) 
{ 
    cout << id << ", " << name << endl; 
} 
int main(int , char *[]) 
{ 
    print(Get<H1>::id, typeid(Get<H1>::type).name()); // prints "A, 2H1", OK 
    print(Get<H2>::id, typeid(Get<H2>::type).name()); // prints "A, 2H2", why? 
    print(Get<H3>::id, typeid(Get<H3>::type).name()); // prints "B, v" , OK 
    print(Get<H4>::id, typeid(Get<H4>::type).name()); // prints "A, 2H4", why? 
} 

我想要一些幫助,以使此代碼的行爲如預期。更具體地說,我希望獲取< H2> ::類型等於,和相同得到< H4> ::類型

+0

可能重複http://stackoverflow.com/questions/3008571/template-specialization-to-use -default-type-if-class-member-typedef-does-not-exi) –

+2

litb的'tovoid'技巧在這個答案中解決了你的問題:http://stackoverflow.com/a/3009891/245265 –

+0

不錯的把戲,天堂我不知道。 – ipc

回答

2

當我給一個+1到@ipc的答案,這是很好的C++ 11啓用編譯器,用於C++編譯器03你應使用不同的方法,因爲函數的模板參數的默認值在C++ 03中不受支持。所以我有這樣的代碼:

​​ [模板專門使用默認的類型,如果類成員的typedef不存在(的
+0

如果你正在使用'boost :: enable_if'('std :: enable_if'是C++ 11),'typename boost :: enable_if :: type'應該也可以工作並且使得'is_type '助手類多餘。 – ipc

+0

@ipc其實我在我的真實項目中使用'boost :: enable_if',但它不是這樣,因爲'boost :: enable_if'的條件應該是'mpl'布爾常量。正確的代碼是'boost :: enable_if >'。請記住'std :: enable_if'屬於'TR1'而不是C++ 11。 – BigBoss

+0

好吧,你是對的。但是'std :: enable_if'仍然是C++ 11,因爲在'std'中嵌入'std :: tr1'是非標準的。 – ipc

2

模板Get<>有一個默認的模板參數 - 這是非常危險的。取決於V是否等於intvoiddouble您會得到不同的結果。這是發生了什麼事情:

Get<H2>::typeGet<H2, void>第一名(與id='A')。現在來檢查,是否有專業化。你的B是Get<U,typename U::der>,它變成Get<U, double>。但這與Get<H2, void>不匹配,因此選擇A。事情變得有趣與Get<H2>::type。然後變體B也是Get<U, void>並提供更好的匹配。但是,該方法不適用於所有類型。

這是我會如何實現Get

template<class U> 
class Get 
{ 
    template <typename T, typename = typename T::der> 
    static typename Get<typename T::der>::type test(int); 
    template <typename T> 
    static T test(...); 
public: 
    typedef decltype(test<U>(0)) type; 
};