传递许多函数并将所有结果存储在元组中

pre*_*eys 10 c++ templates tuples variadic c++14

考虑这个输出:

int foo (int, char) {std::cout << "foo\n";  return 0;}
double bar (bool, double, long ) {std::cout << "bar\n";  return 3.5;}
bool baz (char, short, float) {std::cout << "baz\n";  return true;}

int main() {
    const auto tuple = std::make_tuple(5, 'a', true, 3.5, 1000, 't', 2, 5.8);
    multiFunction<2,3,3> (tuple, foo, bar, baz);  // foo  bar  baz
}
Run Code Online (Sandbox Code Playgroud)

因此,multiFunction<2,3,3>获取前2个元素tuple并将它们传递给foo接下来的3个元素tuple并将它们传递给bar等等...我得到了这个工作(除非函数有重载,这是一个单独的问题).但是所调用的每个函数的返回值都会丢失.我希望将这些返回值存储在某处,例如

std::tuple<int, double, bool> result = multiFunction<2,3,3> (tuple, foo, bar, baz);
Run Code Online (Sandbox Code Playgroud)

但我不知道如何实现这一点.对于那些想要帮助完成这项工作的人来说,这是我目前为止的(更新的)工作代码,它仅将输出存储到字符串流中.不容易获得所有值,特别是如果流中保存的对象是复杂类.

#include <iostream>
#include <tuple>
#include <utility>
#include <sstream>

template <std::size_t N, typename Tuple>
struct TupleHead {
    static auto get (const Tuple& tuple) {  // The subtuple from the first N components of tuple.
        return std::tuple_cat (TupleHead<N-1, Tuple>::get(tuple), std::make_tuple(std::get<N-1>(tuple)));
    }
};

template <typename Tuple>
struct TupleHead<0, Tuple> {
    static auto get (const Tuple&) { return std::tuple<>{}; }
};

template <std::size_t N, typename Tuple>
struct TupleTail {
    static auto get (const Tuple& tuple) {  // The subtuple from the last N components of tuple.
        return std::tuple_cat (std::make_tuple(std::get<std::tuple_size<Tuple>::value - N>(tuple)), TupleTail<N-1, Tuple>::get(tuple));
    }
};

template <typename Tuple>
struct TupleTail<0, Tuple> {
    static auto get (const Tuple&) { return std::tuple<>{}; }
};

template <typename Tuple, typename F, std::size_t... Is>
auto functionOnTupleHelper (const Tuple& tuple, F f, const std::index_sequence<Is...>&) {
    return f(std::get<Is>(tuple)...);
}

template <typename Tuple, typename F>
auto functionOnTuple (const Tuple& tuple, F f) {
    return functionOnTupleHelper (tuple, f, std::make_index_sequence<std::tuple_size<Tuple>::value>{});
}

template <typename Tuple, typename... Functions> struct MultiFunction;

template <typename Tuple, typename F, typename... Fs>
struct MultiFunction<Tuple, F, Fs...> {
    template <std::size_t I, std::size_t... Is>
    static inline auto execute (const Tuple& tuple, std::ostringstream& oss, const std::index_sequence<I, Is...>&, F f, Fs... fs) {
        const auto headTuple = TupleHead<I, Tuple>::get(tuple);
        const auto tailTuple = TupleTail<std::tuple_size<Tuple>::value - I, Tuple>::get(tuple);
    //  functionOnTuple (headTuple, f);  // Always works, though return type is lost.
        oss << std::boolalpha << functionOnTuple (headTuple, f) << '\n';  // What about return types that are void???
        return MultiFunction<std::remove_const_t<decltype(tailTuple)>, Fs...>::execute (tailTuple, oss, std::index_sequence<Is...>{}, fs...);
    }
};

template <>
struct MultiFunction<std::tuple<>> {
    static auto execute (const std::tuple<>&, std::ostringstream& oss, std::index_sequence<>) {  // End of recursion.
        std::cout << std::boolalpha << oss.str();
        // Convert 'oss' into the desired tuple?  But how?
        return std::tuple<int, double, bool>();  // This line is just to make the test compile.
    }
};

template <std::size_t... Is, typename Tuple, typename... Fs>
auto multiFunction (const Tuple& tuple, Fs... fs) {
    std::ostringstream oss;
    return MultiFunction<Tuple, Fs...>::execute (tuple, oss, std::index_sequence<Is...>{}, fs...);
}

// Testing
template <typename T> int foo (int, char) {std::cout << "foo<T>\n";  return 0;}
double bar (bool, double, long ) {std::cout << "bar\n";  return 3.5;}
template <int...> bool baz (char, short, float) {std::cout << "baz<int...>\n";  return true;}

int main() {
    const auto tuple = std::make_tuple(5, 'a', true, 3.5, 1000, 't', 2, 5.8);
    std::tuple<int, double, bool> result = multiFunction<2,3,3> (tuple, foo<bool>, bar, baz<2,5,1>);  // foo<T>  bar  baz<int...>
}
Run Code Online (Sandbox Code Playgroud)

Col*_*mbo 7

这是一种贪婪地推断出参数数量的方法:

#include <tuple>

namespace detail {
    using namespace std;
    template <size_t, size_t... Is, typename Arg>
    constexpr auto call(index_sequence<Is...>, Arg&&) {return tuple<>{};}

    template <size_t offset, size_t... Is, typename ArgT, typename... Fs>
    constexpr auto call(index_sequence<Is...>, ArgT&&, Fs&&...);

    template <size_t offset, size_t... Is,
              typename ArgT, typename F, typename... Fs,
              typename=decltype(declval<F>()(get<offset+Is>(declval<ArgT>())...))>
    constexpr auto call(index_sequence<Is...>, ArgT&& argt, F&& f, Fs&&... fs) {
        return tuple_cat(make_tuple(f(get<offset+I>(forward<ArgT>(argt))...)),
                         call<offset+sizeof...(Is)>(index_sequence<>{},
                                                    forward<ArgT>(argt),
                                                    forward<Fs>(fs)...));}

    template <size_t offset, size_t... Is, typename ArgT, typename... Fs>
    constexpr auto call(index_sequence<Is...>, ArgT&& argt, Fs&&... fs) {
        return call<offset>(index_sequence<Is..., sizeof...(Is)>{},
                            forward<ArgT>(argt), forward<Fs>(fs)...);}
}
template <typename ArgT, typename... Fs>
constexpr auto multifunction(ArgT&& argt, Fs&&... fs) {
    return detail::call<0>(std::index_sequence<>{},
                           std::forward<ArgT>(argt), std::forward<Fs>(fs)...);}
Run Code Online (Sandbox Code Playgroud)

演示.但是,上面的返回值的数量具有二次时间复杂度,因为它tuple_cat是递归调用的.相反,我们可以使用稍微修改的版本call来获取每个调用的索引 -tuple然后直接获得实际值:

#include <tuple>

namespace detail {
    using namespace std;
    template <size_t, size_t... Is, typename Arg>
    constexpr auto indices(index_sequence<Is...>, Arg&&) {return tuple<>{};}

    template <size_t offset, size_t... Is, typename ArgT, typename... Fs>
    constexpr auto indices(index_sequence<Is...>, ArgT&&, Fs&&...);

    template <size_t offset, size_t... Is, typename ArgT, typename F, class... Fs,
             typename=decltype(declval<F>()(get<offset+Is>(declval<ArgT>())...))>
    constexpr auto indices(index_sequence<Is...>, ArgT&& argt, F&& f, Fs&&... fs){
        return tuple_cat(make_tuple(index_sequence<offset+Is...>{}),
                         indices<offset+sizeof...(Is)>(index_sequence<>{},
                                                       forward<ArgT>(argt),
                                                       forward<Fs>(fs)...));}

    template <size_t offset, size_t... Is, typename ArgT, typename... Fs>
    constexpr auto indices(index_sequence<Is...>, ArgT&& argt, Fs&&... fs) {
        return indices<offset>(index_sequence<Is..., sizeof...(Is)>{},
                            forward<ArgT>(argt), forward<Fs>(fs)...);}

    template <typename Arg, typename F, size_t... Is>
    constexpr auto apply(Arg&& a, F&& f, index_sequence<Is...>) {
        return f(get<Is>(a)...);}

    template <typename ITuple, typename Args, size_t... Is, typename... Fs>
    constexpr auto apply_all(Args&& args, index_sequence<Is...>, Fs&&... fs) {
        return make_tuple(apply(forward<Args>(args), forward<Fs>(fs),
                          tuple_element_t<Is, ITuple>{})...);
    }
}

template <typename ArgT, typename... Fs>
constexpr auto multifunction(ArgT&& argt, Fs&&... fs) {
    return detail::apply_all<decltype(detail::indices<0>(std::index_sequence<>{},
                                                         std::forward<ArgT>(argt),
                                                         std::forward<Fs>(fs)...))>
             (std::forward<ArgT>(argt), std::index_sequence_for<Fs...>{},
              std::forward<Fs>(fs)...);}
Run Code Online (Sandbox Code Playgroud)

演示2.

  • 是! 没有水平滚动条! (3认同)