Search code examples
c++templatesc++17variadic-templatestemplate-argument-deduction

How to apply template template parameters in case of variadic template


I'm working on template MyTemplate that is going to be used in following way:

using Alias = MyTemplate<std::pair<int, char>,
                         std::pair<int, double>,
                         std::pair<int, unsigned int>>;

For now we can assume that MyTemplate will take only list of pair types. Moreover, all pair types should have the same first type and second type have to vary.

I want to "catch" the pairs' first_type in MyTemplate. I came up with following definition:

template<typename... Ts>
struct MyTemplate
{
   using first_type = std::decay_t<decltype((Ts::first_type, ...))>;
   // ...
};

When I use typename MyTemplate::first_type in context of different template everything works fine. I only get a warning:

warning: left operand of comma operator has no effect [-Wunused-value]
    using first_type = std::decay_t<decltype((Ts::first_type, ...))>;
                                                                    ^

However, I cannot create instance of Alias because I get that error:

error: missing 'typename' prior to dependent type name 'std::pair<int, char>::first_type'

Do you gave any idea for "generic" solution? I can use C+17.


Solution

  • For now we can assume that MyTemplate will take only list of pair types. Moreover, all pair types should have the same first type and second type have to vary.

    I want to "catch" the pairs' first_type in MyTemplate.

    Not sure but it seems to me that your looking something as follows

    template <typename...>
    struct MyTemplate;
    
    template <typename FT, typename ... STs>
    struct MyTemplate<std::pair<FT, STs>...>
     {
       using first_type = FT;
     };
    

    You can verify

    using Alias = MyTemplate<std::pair<int, char>,
                             std::pair<int, double>,
                             std::pair<int, unsigned int>>;
    
    static_assert( std::is_same<int, typename Alias::first_type>::value, "!" );
    

    This way you also impose that the template parameters of MyTemplate are all std::pairss with a common first_type.

    Otherwise, without template specialization and maintaining you way, you can use std::tuple/std::tuple_element_t

    template <typename ... Ts>
    struct MyTemplate
     {
       using first_type = std::tuple_element_t<0, std::tuple<typename Ts::first_type...>>;
     };