Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I strip a tuple<> back into a variadic template list of types?

Is there a way to strip a std::tuple<T...> in order to get it back to T...?

Example

Suppose vct<T...> is a pre-existing variadic class template,

using U = std::tuple<int,char,std::string>;
using X = vct<int,char,std::string>;
using Y = vct< strip<U> >;            // should be same as X

Notes

I know about std::tuple_element, but I need all the elements, in a form that is usable as T...

For reference, I have found this question, which is similar, but my needs are somewhat simpler (so I hope there is a simpler solution): all I need is the list of types that are in the tuple - I don't care about the actual values of a tuple instance.

like image 647
kfmfe04 Avatar asked Mar 14 '13 19:03

kfmfe04


3 Answers

template<typename>
struct strip;

template<typename ...T>
struct strip<std::tuple<T...>>
{
   using type = vct<T...>;
};

then use this as:

using Y = strip<U>::type;

Now Y is same as X.

like image 136
Nawaz Avatar answered Nov 11 '22 01:11

Nawaz


No, this is not possible. Argument packs are the result of type deduction, and they can't be produced in other contexts.

You could do something similar to what you're asking for this way:

template<template<typename...> class T, typename>
struct instantiate_with_arg_pack { };

template<template<typename...> class T, typename... Ts>
struct instantiate_with_arg_pack<T, std::tuple<Ts...>>
{
    using type = T<Ts...>;
};

template<typename... Ts>
struct vct { };

int main()
{
    using U = std::tuple<int,char,std::string>;
    using X = vct<int,char,std::string>;
    using Y = instantiate_with_arg_pack<vct, U>::type;
}

Actually, you don't need to hold the argument pack in a tuple: any variadic class template is OK:

template<template<typename...> class T, typename>
struct instantiate_with_arg_pack { };

template<
    template<typename...> class T, 
    template<typename...> class U, // <===
    typename... Ts
    >
struct instantiate_with_arg_pack<T, U<Ts...>>
//                                   ^^^^^^^^
{
    using type = T<Ts...>;
};

template<typename... Ts>
struct vct { };

int main()
{
    using U = std::tuple<int,char,std::string>;
    using X = vct<int,char,std::string>;
    using Y = instantiate_with_arg_pack<vct, X>::type;
    //                                        ^

    // Won't fire
    static_assert(
        std::is_same<Y, vct<int,char,std::string>>::value, 
        "Error!");
}

And here is a live example.

like image 23
Andy Prowl Avatar answered Nov 10 '22 23:11

Andy Prowl


You can not directly "return" a parameter pack, so what you need is something like this:

template< typename... Ts >
struct vct
{ ... };

template< typename T >
struct make_vct;

template< typename... Ts >
struct make_vct< std::tuple< Ts... > >
{
    typedef vct< Ts... > type;
};

and use

using Y = make_vct< U >::type;
like image 4
Daniel Frey Avatar answered Nov 11 '22 01:11

Daniel Frey