effective way to select last parameter of variadic template

后端 未结 8 899
温柔的废话
温柔的废话 2020-12-01 12:37

I know how to select first parameter of variadic template:

template< class...Args> struct select_first;
template< class A, class ...Args> struct          


        
8条回答
  •  暖寄归人
    2020-12-01 13:11

    Same approach as last time, O(logN) instantiation depth. Using only one overload, so it should consume less resources.

    Warning: it currently removes references from the tuple types. Note: Removed the reference from pack::declval. I think it still works in every case.

    indices trick in O(log(N)) instantiations, by Xeo; modified to use std::size_t instead of unsigned

        #include 
    
        // using aliases for cleaner syntax
        template using Invoke = typename T::type;
    
        template struct seq{ using type = seq; };
    
        template struct concat;
    
        template
        struct concat, seq>
          : seq{};
    
        template
        using Concat = Invoke>;
    
        template struct gen_seq;
        template using GenSeq = Invoke>;
    
        template
        struct gen_seq : Concat, GenSeq>{};
    
        template<> struct gen_seq<0> : seq<>{};
        template<> struct gen_seq<1> : seq<0>{};
    

    Today, I realized there's a different, simpler and probably faster (compilation time) solution to get the nth type of a tuple (basically an implementation of std::tuple_element). Even though it's a direct solution of another question, I'll also post it here for completeness.

    namespace detail
    {
        template
        struct Any
        {
            template Any(T&&) {}
        };
    
        template
        struct wrapper {};
    
        template
        struct get_nth_helper
        {
            template
            static T deduce(Any..., wrapper, ...);
        };
    
        template
        auto deduce_seq(seq, wrapper... pp)
        -> decltype( get_nth_helper::deduce(pp...) );
    }
    
    #include 
    
    template
    struct tuple_element;
    
    template
    struct tuple_element>
    {
        using type = decltype( detail::deduce_seq(gen_seq{},
                                                  detail::wrapper()...) );
    };
    

    Helper for last element:

    template
    struct tuple_last_element;
    
    template
    struct tuple_last_element>
    {
        using type = typename tuple_element> :: type;
    };
    

    Usage example:

    #include 
    #include 
    int main()
    {
        std::tuple t{42, true, 'c'};
    
        tuple_last_element::type x = 'c'; // it's a reference
    
        static_assert(std::is_same{}, "!");
    }
    

    Original version:

    #include 
    #include 
    
    namespace detail
    {
        template
        struct get_last_helper;
    
        template
        struct get_last_helper< seq, TT... >
        {
            template
            struct pack {};
            template
            struct pack
            {
                T declval();
            };
    
            // this needs simplification..
            template
            struct exp : TTpacked...
            {
                static auto declval_helper()
                    -> decltype(std::declval().declval());
                using type = decltype(declval_helper());
            };
    
            using type = typename exp...>::type;
        };
    }
    
    template< typename Tuple >
    struct get_last;
    
    template< typename... TT >
    struct get_last>
    {
        template
        static seq helper(seq);
        using seq_t = decltype(helper(gen_seq()));
    
        using type = typename detail::get_last_helper::type;
    };
    
    
    int main()
    {
        using test_type = std::tuple;
    
        static_assert(std::is_same::type>::value, "!");
        // fails:
        static_assert(std::is_same::type>::value, "!");
    }
    

提交回复
热议问题