Search code examples
c++templatesc++11boostboost-fusion

Extracting a tuple of value_type from a tuple of containers in C++11


I have a function with a template parameter which I know to be a std::tuple of several standard C++ containers of varying element types. How can I extract, out of this, a type that is a std::tuple of the element types?

For example, suppose I have the following function

template <typename TupOfCtrs>
void doStuff(const TupOfCtrs& tupOfCtrs) {
    using TupOfElements = /*extract a tuple type by applying CtrT::value_type to each container in tupOfCtrs and combining the results into an std::tuple*/;
    MyHelperClass<TupOfElements> helper;
}

and I know it is being called like this:

std::list<Foo> l {/*...*/};
std::vector<Bar> v {/*...*/};
std::deque<Baz> d {/*...*/};
auto tup = std::make_tuple(l, v, d);

In this case, I want the TupOfElements helper type to be defined as std::tuple<Foo, Bar, Baz>. Note that I do not need to actually create the tuple, only to get its type.

How can this be achieved, possibly using the Boost::Fusion library?


Solution

  • You can do this even in a more simple manner without Boost Fusion like this:

    // Template which takes one type argument:
    template <typename Tuple> struct TupOfValueTypes;
    
    // Only provide a definition for this template for std::tuple arguments:
    // (i.e. the domain of this template metafunction is any std::tuple)
    template <typename ... Ts>
    struct TupOfValueTypes<std::tuple<Ts...> > {
        // This definition is only valid, if all types in the tuple have a
        // value_type type member, i.e. the metafunction returns a type only
        // if all types of the members in the std::tuple have a value_type
        // type member, and a std::tuple can be constructed from these:
        using type = std::tuple<typename Ts::value_type...>;
    };
    
    template <typename TupOfCtrs>
    void doStuff(const TupOfCtrs& tupOfCtrs) {
        using TupOfElements = typename TupOfValueTypes<TupOfCtrs>::type;
        // ...
    }
    

    But it is of course easier to specify doStuff for the std::tuple explicitly:

    template <typename ... Ts>
    void doStuff(const std::tuple<Ts...> & tupOfCtrs) {
        using TupOfElements = std::tuple<typename Ts::value_type...>;
        // ...
    }
    

    PS: Also note, that in many cases if you need to just have a list of types, the std::tuple class is an overkill, and might slightly hurt compilation times. Personally, I've always instead used a simple TypeList struct:

    template <typename ... Ts> struct TypeList
    { using type = TypeList<Ts...>; };