如何使用元组元素作为参数来部分地使用函数来调用函数

时间:2017-06-25 06:07:23

标签: c++ templates variadic-templates variadic-functions

我试图使用解压缩的元组调用函数,但我遇到了问题。我的代码依赖于在函数为零时对函数执行特殊情况的能力。此代码不起作用,但我如何使用有效的c ++实现此目的?

//Initialize Recursion
template <class ret, class ... Ts>
ret templateHelpers::callFunctionFromTuple(ret (*function)(Ts...), std::tuple<Ts...> tuple) {
    return callFunctionFromTupleHelper<sizeof...(Ts), ret>(function, tuple);
}

//Recursively break down the tuple
template <int NumLeft, class ret, class ... ArgsF, class ... ArgsT, class ... Args>
ret templateHelpers::callFunctionFromTupleHelper(ret (*function)(ArgsF...), std::tuple<ArgsT...> tuple, Args... ts) {
    return callFunctionFromTuple<numLeft - 1, ret>(funcTs(function, std::tuple<Tuples...> tuple, std::get<NumLeft-1>(tuple) Ts... ts));
}

//Finally Call the Function
//TODO: fix the error. Partial specialization does not work, including that <0>
template <class ret, class ... ArgsF, class ... ArgsT, class ... Args>
ret templateHelpers::callFunctionFromTupleHelper<0>(ret (*function)(ArgsF...), std::tuple<ArgsT...> tuple, Args... ts) {
    return func(ts...);
}

PS我正在使用VS2017

4 个答案:

答案 0 :(得分:4)

C ++中没有模板函数的部分特化。让您的函数遵循可以部分专业化的类模板。

namespace detail {
  template<...>
  struct callFunctionFromTupleImpl {
    static ret do_call(...) {
    }
  };

  // + more partial specializations
}

template <class ret, class ... Ts>
ret callFunctionFromTuple(ret (*function)(Ts...), std::tuple<Ts...> tuple) {
    return detail::callFunctionFromTupleHelperImpl<ret, Ts...>::do_call(function, tuple);
}

答案 1 :(得分:1)

In addition to what @StoryTeller said,因为我写了一个完整的转发完整的解决方案而不知道已经有一个已发布的答案,这是

如果您不想考虑possible implementation from cppreference for std::apply并修改它以适合您的计划。您需要将调用委托给结构

#include <tuple>
#include <cassert>

namespace detail {
    template <int Size>
    struct InvokeHelper {
        template <typename Func, typename TupleType, typename... Args>
        static decltype(auto) apply(Func&& func, TupleType&& tup,
                                    Args&&... args) {
            constexpr auto tuple_size =
                std::tuple_size<std::decay_t<TupleType>>::value;
            return InvokeHelper<Size - 1>::apply(
                    std::forward<Func>(func),
                    tup,
                    std::forward<Args>(args)...,
                    std::get<tuple_size - Size>(
                        std::forward<TupleType>(tup)));
        }
    };
    template <>
    struct InvokeHelper<0> {
        template <typename Func, typename TupleType, typename... Args>
        static decltype(auto) apply(Func&& func, TupleType&&, Args&&... args) {
            return std::forward<Func>(func)(std::forward<Args>(args)...);
        }
    };
} // namespace detail

template <typename Func, typename TupleType>
decltype(auto) invoke_tuple(Func&& func, TupleType&& tup) {
    constexpr auto tuple_size = std::tuple_size<std::decay_t<TupleType>>::value;
    return detail::InvokeHelper<tuple_size>::apply(
            std::forward<Func>(func), std::forward<TupleType>(tup));
}

int main() {
    auto tup = std::make_tuple(1, 2);
    assert(invoke_tuple([](int a, int b) { return a + b; }, tup) == 3);
}

答案 2 :(得分:1)

解压std::tuple的更简单方法是使用sdt::index_sequence

#include<utility>
#include<tuple>

template<typename Ret, typename... Ts, size_t... I>
Ret callFunction_(Ret (*fn)(Ts...), std::tuple<Ts...> tup, std::index_sequence<I...>)
{
    return fn(std::get<I>(tup)...);
}

template<typename Ret, typename... Ts, typename Tuple>
Ret callFunction(Ret (*fn)(Ts...), Tuple&& tup)
{
    return callFunction_(fn, std::forward<Tuple>(tup),
        std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>{}>{});
}

Live

然后不需要授权给类模板:)

答案 3 :(得分:0)

您还可以使用std :: enable_if实现所需的功能。如果有任何拼写错误,请提前道歉,因为接下来几天我不会在电脑附近。

template <std::size_t N, typename ret>
typename std::enable_if<N != 0, ret>::type f
(
)
{
    return f<N-1, ret>();
}

template <std::size_t N, typename ret>
typename std::enable_if<N == 0, ret>::type f
(
)
{
    return ret();
}