2012-07-13 33 views
6

Tôi muốn làm một cái gì đó như thế này:Tôi làm cách nào để có được một loại cụ thể từ gói loại variadic?

template<typename ...T> struct foo 
{ 
    bar<0 /*to index through types in pack*/ ,T...>::type var1; 
    bar<1 /*to index through types in pack*/ ,T...>::type var2; 
    ... 
} 

Nhưng làm thế nào tôi sẽ xác định bar? Không có kỹ thuật đệ quy nào đến với tâm trí để làm điều này.

Tôi muốn có một kỹ thuật chung để tôi có thể nhập bất kỳ loại cụ thể nào từ gói loại, không chỉ hai loại được hiển thị trong ví dụ.

+0

Những gì bạn muốn var1 và var2 là nếu sizeof ... (T) == 0 hoặc sizeof ... (T) == 1 ? – Andrzej

+3

Tại sao không chỉ sử dụng 'std :: tuple '? Truy cập các phần tử dưới dạng 'std :: nhận được (tup)' và các loại như 'std :: tuple_element > :: type'. – Xeo

+0

@ Xeo bạn nói đúng nhưng tôi muốn học kỹ thuật cơ bản để làm việc với các mẫu var. Tôi hy vọng bạn sẽ hiểu. – M3taSpl0it

Trả lời

5
#include <iostream> 
#include <typeinfo> 

template<class T, class T2, class... Args> 
class C 
{ 
public: 
    typedef T type1; 
    typedef T2 type2; 
}; 

int main() 
{ 
    typedef C<int, double, int, float> c; 
    std::cout << typeid(c::type1).name() << " " << typeid(c::type2).name() << std::endl; 
} 

hoặc mb một cái gì đó như thế này.

#include <iostream> 
#include <typeinfo> 

template<int N, class T, class... Args> 
struct expand 
{ 
public: 
    typedef typename expand<N - 1, Args...>::type type; 
}; 

template<class T, class... Args> 
struct expand<1, T, Args...> 
{ 
public: 
    typedef T type; 
}; 

template<class... Args> 
class argsExpander 
{ 
public: 
    typedef typename expand<1, Args...>::type type1; 
    typedef typename expand<2, Args...>::type type2; 
}; 

template<class... Args> 
class C 
{ 
public: 
    typename argsExpander<Args...>::type1 var1; 
    typename argsExpander<Args...>::type2 var2; 
}; 

int main() 
{ 
    C<int, double, int, float> c; 
    std::cout << typeid(c.var1).name() << " " << typeid(c.var2).name() << std::endl; 
} 

http://liveworkspace.org/code/7de289f128e86eb6006f576cbaf98991

+0

Tôi nghĩ câu hỏi ngụ ý rằng phần 'typedef' sẽ xảy ra tự động –

+2

Thành ngữ' expand' đó khá thông minh. Mã số – tenfour

+0

@refp được cập nhật. – ForEveR

1

Vâng, bạn có thể làm điều này với đệ quy ... trên thực tế bạn có nhiều hoặc ít hơn được triển khai lại std::tuple (và ngầm std::get).

Công việc khó khăn đến khi truy cập các thành viên, vì bạn không thể gọi cho họ var1, var2, trừ khi bạn đặt tên chúng theo cách thủ công.

template <typename... TypeList> struct foo; 

template <typename Head, typename... Tail> 
struct foo<Head, Tail...>: public foo<Tail...> 
{ 
    Head var; 
}; 

Tôi đã sử dụng thừa kế ở đây, nhưng thành phần (sử dụng thành viên foo<Tail...> tail) hoạt động là tốt.

Bây giờ, nếu loại của bạn là duy nhất, bạn có thể truy cập vào các thành viên theo loại ...

// this overload if VarType is the first 
template <typename VarType, typename... FooTail> 
VarType& foo_get(foo<VarType, FooTail...>& f) 
{ 
    return f.var; 
} 

// this overload to walk down to foo's parent 
template <typename VarType, typename FooHead, typename... FooTail> 
VarType& foo_get(foo<FooHead, FooTail...>& foo) 
{ 
    return foo_get<VarType>(static_cast<foo<FooTail...>>(f)); 
} 

// call like: 
// int &x = foo_get<int>(my_foo_object); 

hoặc bạn có thể truy cập bằng cách vị trí:

template <int N, typename... TypeList> struct GetHelper; 

template <typename Head, typename... Tail> 
struct GetHelper<0, Head, Tail...> 
{ 
    static Head& get(foo<Head, Tail...> &f) { return f.var; } 
}; 

template <int N, typename Head, typename... Tail> 
struct GetHelper<N, Head, Tail...>: public GetHelper<N-1, Tail...> 
{}; 

template <int N, typename... TypeList> 
auto foo_get(foo<TypeList...> &f) 
    -> GetHelper<N, TypeList...>::get(*static_cast<foo<TypeList...>*>(0)) 
{ 
    return GetHelper<N, TypeList...>::get(f) 
} 

// call like: 
// int &x = foo_get<2>(my_foo_object); 

cả những có thể được cải thiện để nhận được báo cáo lỗi tốt hơn (và mặc dù tôi đã sử dụng cả hai kỹ thuật, tôi thậm chí không cố gắng biên dịch mã mẫu này)

+2

Thay vì reimplementing 'std :: tuple', OP chỉ nên sử dụng nó. – Xeo

+0

Tôi đồng ý, nhưng vì OP thích giải pháp dường như không phù hợp với câu hỏi, tôi không chắc tôi có hiểu câu hỏi này hay không. – Useless

1

Nếu tôi hiểu câu hỏi của bạn một cách chính xác, bạn muốn thực hiện điều gì đó tương tự o std :: tuple:

Tôi nghĩ rằng tuple được thực hiện theo cách này:

template <class T> 
class tuple 
{ 
    T mem; 
}; 

template <class T, class... REST> 
class tuple : tuple<REST...> 
{ 
    T mem; 
}; 
1

Đơn giản chỉ cần sử dụng std :: tuple như @Xeo tiếp tục cho ý kiến. Nó thuận tiện và thực hiện chính xác những gì bạn cố gắng làm.

Trích:

Tại sao không chỉ cần sử dụng một std::tuple<T...>?

yếu tố Access std::get<I>(tup)

loại như std::tuple_element<I, std::tuple<T...>>::type

Các vấn đề liên quan