Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unpacking a typelist

Lets say I have a function that takes just a type template parameter, I cannot change it's definition/implementation.

template < typename T >
void do_it();

Now I have a typelist defined a usual way, can't change it either:

template< typename ...Ts >
struct typelist;

I want to implement a function that takes a typelist, and runs do_it() on every type:

template< typename List >
void do_them();

The only solution I found up 'till now is:

template< typename T >
void do_them_impl()
{
   do_it<T>();
}

template< typename T, typename Ts...>
void do_them_impl()
{
   do_it<T>();
   do_them_impl<Ts...>();
}

template< template < typename...> class List, typename ...Ts >
void do_them_extract( List<Ts...>&& )
{
    do_them_impl< Ts >(); 
}

template< typename List >
void do_them()
{
    do_them_impl( List{} ); 
}

But that requires 4(!) functions for each case I want to create a single do_them function. I will require quite a few of those, and I don't want to write a quad of functions for each. Am I missing something?

C++14 welcome, C++17 solutions too, but marked as such.

like image 520
Kornel Kisielewicz Avatar asked Feb 02 '17 12:02

Kornel Kisielewicz


1 Answers

In C++14 you can use some awful tricks to introduce a valid pack expansion context:

template< template < typename...> class List, typename ...Ts >
void do_them_impl( List<Ts...>&& )
{
    (void)std::initializer_list<int> {
        (do_it<Ts>(), 0)...  
    };
}

template< typename List >
void do_them()
{
    do_them_impl( List{} ); 
}

This allows you to avoid recursive template instantiation, which is generally more expensive.

Live Demo


In C++17 you can use fold expressions:

template< template < typename...> class List, typename ...Ts >
void do_them_impl( List<Ts...>&& )
{       
    (do_it<Ts>(), ...);
}

template< typename List >
void do_them()
{
    do_them_impl( List{} ); 
}

Live Demo

like image 169
TartanLlama Avatar answered Oct 13 '22 09:10

TartanLlama