2012-07-13 11 views
6

chciałbym zrobić coś takiego:Jak uzyskać określony typ z pakietu typu 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; 
    ... 
} 

Ale jak ja bym zdefiniował bar? W tym celu nie przychodzi na myśl technika rekursji.

Chcę ogólnej techniki, aby móc typedef określonego rodzaju z pakietu typu, a nie tylko dwóch pokazanych w przykładzie.

+0

Czego chcesz var1 i var2 być ... jeśli sizeof (T) == 0 lub sizeof ... (T) == 1 ? – Andrzej

+3

Dlaczego po prostu nie używać 'std :: tuple '? Dostęp do elementów jako 'std :: get (tup)' i typy jako 'std :: tuple_element > :: type'. – Xeo

+0

@Xeo masz rację, ale chcę nauczyć się podstawowej techniki pracy z szablonami var. Mam nadzieję, że zrozumiesz. – M3taSpl0it

Odpowiedz

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; 
} 

lub coś podobnego.

#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

Myślę, że pytanie sugeruje, że sekcja 'typedef' powinna się automatycznie wydarzyć –

+2

Ten idiom' expand' jest całkiem sprytny. – tenfour

+0

Kod @ refp został zaktualizowany. – ForEveR

1

Tak, można to zrobić z rekursji ... w rzeczywistości jesteś bardziej lub mniej ponownego wdrażania std::tuple (i pośrednio std::get).

Ciężka praca ma na celu uzyskanie dostępu do członków, ponieważ nie można ich nazwać var1, var2 itd., Chyba że ręcznie je nazwiesz.

template <typename... TypeList> struct foo; 

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

Użyłem dziedziczenie tutaj, ale kompozycja (za pomocą elementu foo<Tail...> tail) działa tak samo.

Teraz, jeśli typy są wyjątkowe, można uzyskać dostęp do elementu według rodzaju ...

// 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); 

czy można uzyskać dostęp przez stanowisko:

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); 

oba te można poprawić, aby lepiej raportować błędy (i chociaż użyłem obu tych technik, nawet nie próbowałem skompilować tego przykładowego kodu)

+2

Zamiast ponownego wdrażania 'std :: tuple', PO powinien po prostu z niego korzystać. – Xeo

+0

Zgadzam się, ale ponieważ OP podobało się rozwiązanie, które nie pasuje do tego pytania, nie jestem pewien, czy w ogóle rozumiem pytanie. – Useless

1

Jeśli dobrze rozumiem twoje pytanie, chcesz zaimplementować coś podobnego o std :: krotka:

myślę, że krotka jest realizowany w ten sposób:

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

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

Wystarczy użycie std :: krotka jako @Xeo utrzymuje komentowania. Jest to wygodne i robi dokładnie to, co próbujesz zrobić.

Cytat:

Dlaczego nie wystarczy użyć std::tuple<T...>?

elementy Access jako std::get<I>(tup) i

typy jak std::tuple_element<I, std::tuple<T...>>::type

Powiązane problemy