c++metaprogrammingtemplate-meta-programmingc++23

Typename packing is failed in C++


Here is code:

aml::type_list<int,int,char,std::string> example;
std::tuple_element_t<2,std::tuple<decltype(example)>> a = 'b';

But when i try to run code it says, static assertion is failed because ( 2 < 1 ) failed. I know it is probably because it takes decltype(example) as one type or it takes onlt first type.

Could you explain me is there any way of unpacking these like decltype... or something like that i can use in order to pass all types to this function.


Solution

  • The expansion of std::tuple<decltype(example)> will be:

    std::tuple<aml::type_list<int,int,char,std::string>>
    

    in which the tuple has only one type, aml::type_list<int,int,char,std::string>. You need to move the type_list parameter types to a tuple (tuple-like) if you want to use tuple_element on the result.

    Example:

    namespace aml {
    template <template <class...> class To, template <class...> class From,
              class... Ts>
    auto helper(From<Ts...>) -> To<Ts...>;
    
    template <template <class...> class To, class T>
    using move_type_params = decltype(helper<To>(std::declval<T>()));
    }  // namespace aml
    

    Or in a more compact way using a lambda instead of a separate helper function template:

    namespace aml {
    template <template <class...> class To, class T>
    using move_type_params =
        decltype([]<template <class...> class From, class... Ts>(
                     From<Ts...>) -> To<Ts...> {}(std::declval<T>()));
    }  // namespace aml
    

    Usage:

    int main() {
        aml::type_list<int, int, char, std::string> example;
    
        std::tuple_element_t<2,
                             aml::move_type_params<std::tuple, decltype(example)>>
            a = 'b';
    }
    

    Here aml::move_type_params creates the type std::tuple<int, int, char, std::string> from your aml::type_list<int, int, char, std::string>.


    If you are going to create std::tuple-types like this a lot, you could add a helper which uses move_type_params with std::tuple hardcoded as the template template parameter type:

    namespace aml {
    template <class T>
    using as_tuple_type = move_type_params<std::tuple, T>;
    }  // namespace aml
    
    int main() {
        aml::type_list<int, int, char, std::string> example;
    
        std::tuple_element_t<2, aml::as_tuple_type<decltype(example)>> a = 'b';
    }