effective way to select last parameter of variadic template

后端 未结 8 901
温柔的废话
温柔的废话 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:34

    A pretty dumb approach would be to write a helper class and specialize for each number of parameters (up to some limit of your choice). You could use preprocessor for that.

    template<typename...>
    struct select_last_helper;
    
    template<typename T1>
    struct select_last_helper<T1> {
        using type = T1;
    };
    
    template<typename T1, typename T2>
    struct select_last_helper<T1,T2> {
        using type = T2;
    };
    
    template<typename T1, typename T2, typename T3>
    struct select_last_helper<T1,T2,T3> {
        using type = T3;
    };
    
    template<typename... Ts>
    struct select_last {
        using type = typename select_last_helper<Ts...>::type;
    };
    

    O(1) template instantiations :)

    0 讨论(0)
  • 2020-12-01 13:35

    This other solution is brilliant if C++17 is available and if one is interested in the last type only.

    If C++14 support is required (C++11 plus index_sequence) or if one is interested in the nth type then a good solution is

    #include <utility>
    
    ////////////////////////////////////////////////////////////////////////////////
    
    template<std::size_t n, std::size_t i, class>
    struct type_if_equal {
      static_assert(n != i, "see specialization");
    // missing `type` typedef by purpose
    };
    
    template<std::size_t n, class T>
    struct type_if_equal<n, n, T> {
      using type = T;
    };
    
    ////////////////////////////////////////////////////////////////////////////////
    
    template<std::size_t n, class Is, class... Ts>
    struct select_nth;
    
    template<std::size_t n, std::size_t... is, class... Ts>
    struct select_nth<n, std::index_sequence<is...>, Ts...>
      : type_if_equal<n, is, Ts>...
    {};
    
    template<std::size_t n, class... Ts>
    using select_nth_t = typename select_nth<
      n, std::index_sequence_for<Ts...>, Ts...
    >::type;
    
    ////////////////////////////////////////////////////////////////////////////////
    
    template<class T0, class... Ts>
    using select_last_t = select_nth_t<sizeof...(Ts), T0, Ts...>;
    
    ////////////////////////////////////////////////////////////////////////////////
    
    int main() {
      using T = select_last_t<int, double, double, long, long, long, int, char>;
      static_assert(std::is_same<T, char>{}, "");
    }
    

    Warning: Do not use a naive self-made solution like select_nth_t if you need fast compilation times for huge variadic lists. There are highly optimized template-metaprogramming libraries for this purpose. Have a look at metaben.ch for a comparison of compile-time performance of several algorithms. This algorithm is called at, and here is my measurement result of select_nth_t based on this code using GCC 10:

    See blog posts by Louis Dionne and Odin Holmes for excellent background information regarding compile-time reduction of the at algorithm (a.k.a. std::tuple_element_t).

    0 讨论(0)
提交回复
热议问题