How do I expand a tuple into variadic template function's arguments?

前端 未结 13 1282
旧时难觅i
旧时难觅i 2020-11-22 07:49

Consider the case of a templated function with variadic template arguments:

template Tret func(const T&... t);
         


        
13条回答
  •  情书的邮戳
    2020-11-22 08:26

    Extending on @David's solution, you can write a recursive template that

    1. Doesn't use the (overly-verbose, imo) integer_sequence semantics
    2. Doesn't use an extra temporary template parameter int N to count recursive iterations
    3. (Optional for static/global functors) uses the functor as a template parameter for compile-time optimizaion

    E.g.:

    template 
    struct static_functor {
        template 
        static inline auto apply(const std::tuple& t, Args_tmp... args)
                -> decltype(func(std::declval()...)) {
            return static_functor::apply(t, args...,
                    std::get(t));
        }
        template 
        static inline auto apply(const std::tuple& t, T... args)
                -> decltype(func(args...)) {
            return func(args...);
        }
    };
    
    static_functor::apply(my_tuple);
    

    Alternatively if your functor is not defined at compile-time (e.g., a non-constexpr functor instance, or a lambda expression), you can use it as a function parameter instead of a class template parameter, and in fact remove the containing class entirely:

    template 
    inline auto apply_functor(F&& func, const std::tuple& t,
            Args_tmp... args) -> decltype(func(std::declval()...)) {
        return apply_functor(func, t, args..., std::get(t));
    }
    template 
    inline auto apply_functor(F&& func, const std::tuple& t,
            T... args) -> decltype(func(args...)) {
        return func(args...);
    }
    
    apply_functor(&myFunc, my_tuple);
    

    For pointer-to-member-function callables, you can adjust either of the above code pieces similarly as in @David's answer.

    Explanation

    In reference to the second piece of code, there are two template functions: the first one takes the functor func, the tuple t with types T..., and a parameter pack args of types Args_tmp.... When called, it recursively adds the objects from t to the parameter pack one at a time, from beginning (0) to end, and calls the function again with the new incremented parameter pack.

    The second function's signature is almost identical to the first, except that it uses type T... for the parameter pack args. Thus, once args in the first function is completely filled with the values from t, it's type will be T... (in psuedo-code, typeid(T...) == typeid(Args_tmp...)), and thus the compiler will instead call the second overloaded function, which in turn calls func(args...).

    The code in the static functor example works identically, with the functor instead used as a class template argument.

提交回复
热议问题