2012-11-24 67 views
5

Tôi đang cố gắng để thực hiện một mẫu lớp (tên Nhận <> đây) rằng, đưa ra một cấu trúc H, loại Get<H>::typeH bản thân nếu qualified-idH::der không tồn tại, và là Get<H::der>::type khác . Tôi không thể hiểu điều gì sai với mã sau:C++ loại đệ quy đặc điểm mà

#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? 
} 

Tôi muốn được trợ giúp làm cho mã này hoạt động như mong đợi. Cụ thể hơn, tôi ước rằng Nhận < H2> :: loại bằng đôi và tương tự cho Nhận < H4> :: loại.

+0

thể trùng lặp của [Template chuyên môn hóa để sử dụng loại mặc định nếu thành viên lớp typedef không tồn tại] (http://stackoverflow.com/questions/3008571/template-specialization-to-use -default-type-if-class-member-typedef-does-not-exi) –

+2

mẹo 'tovoid' của litb trong câu trả lời này giải quyết được vấn đề của bạn: http://stackoverflow.com/a/3009891/245265 –

+0

lừa đẹp, thiên đường Không biết điều đó. – ipc

Trả lời

2

Trong khi tôi cung cấp cho một +1 đến @ipc câu trả lời và nó là rất tốt cho C++ 11 trình biên dịch được kích hoạt, cho C++ 03 trình biên dịch bạn nên sử dụng một cách tiếp cận khác, vì giá trị mặc định cho các đối số mẫu của một hàm không được hỗ trợ trong C++ 03. Vì vậy, tôi có mã này:

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

template< class T > 
struct is_type { 
    static const bool value = true; 
}; 

template<class U> 
struct Get<U, 
    typename std::tr1::enable_if<is_type<typename U::der>::value, void>::type> 
{ 
    static const char id = 'B'; 
    typedef typename Get<typename U::der>::type type; 
}; 
+0

Nếu bạn đang sử dụng 'boost :: enable_if' (' std :: enable_if' là C++ 11), 'typename boost :: enable_if :: type' cũng hoạt động và làm cho' is_type 'lớp helper thừa. – ipc

+0

@ipc Thực ra tôi đang sử dụng 'boost :: enable_if' trong dự án thực của mình nhưng không phải như vậy, vì điều kiện' boost :: enable_if' phải là hằng số boolean 'mpl'. mã đúng là 'boost :: enable_if >'. Và hãy nhớ 'std :: enable_if' thuộc về' TR1' chứ không phải C++ 11. – BigBoss

+0

ok, bạn nói đúng. Nhưng 'std :: enable_if' vẫn là C++ 11 vì việc nhúng« std :: tr1' vào 'std' là không chuẩn. – ipc

2

Mẫu Get<> có thông số mẫu mặc định - điều này rất nguy hiểm. Tùy thuộc vào việc V có bằng int, void hoặc double bạn nhận được kết quả khác nhau hay không. Đây là những gì sẽ xảy ra:

Get<H2>::type là địa chỉ đầu tiên (với id='A'). Bây giờ đến kiểm tra, cho dù có một chuyên môn của nó. B của bạn là Get<U,typename U::der> trở thành Get<U, double>. Nhưng điều này không phù hợp với whith Get<H2, void>, do đó, A được chọn. Mọi thứ trở nên thú vị với Get<H2>::type. Sau đó, biến thể B cũng là Get<U, void> và cung cấp kết quả phù hợp hơn. Tuy nhiên, cách tiếp cận này không thể làm việc cho tất cả các loại.

Đây là cách tôi sẽ thực hiện 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; 
}; 
Các vấn đề liên quan