Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get a specific type from a variadic type pack?

I wish to do something like this:

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

But how would I define bar? No recursion technique comes to mind to do this.

I want a general technique so that I could typedef any particular type from a type pack, not just the two shown in the example.

like image 359
M3taSpl0it Avatar asked Jul 13 '12 11:07

M3taSpl0it


People also ask

What is a variadic template c++?

Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.

What is parameter pack in c++?

Parameter packs (C++11) A parameter pack can be a type of parameter for templates. Unlike previous parameters, which can only bind to a single argument, a parameter pack can pack multiple parameters into a single parameter by placing an ellipsis to the left of the parameter name.

What is Pack expansion?

Pack expansion A pattern followed by an ellipsis, in which the name of at least one parameter pack appears at least once, is expanded into zero or more comma-separated instantiations of the pattern, where the name of the parameter pack is replaced by each of the elements from the pack, in order. template<class...


2 Answers

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

or mb something like this.

#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

like image 168
ForEveR Avatar answered Nov 03 '22 23:11

ForEveR


Yes, you can do this with recursion ... in fact you're more-or-less re-implementing std::tuple (and implicitly std::get).

The hard work comes in accessing the members, since you can't call them var1, var2 etc. unless you're manually naming them.

template <typename... TypeList> struct foo;

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

I've used inheritance here, but composition (using a foo<Tail...> tail member) works as well.

Now, if your types are unique, you can access the member by type ...

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

or you can access by position:

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

both of those can be improved to get better error reporting (and although I've used both techniques, I haven't even tried to compile this sample code)

like image 20
Useless Avatar answered Nov 04 '22 00:11

Useless