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

前端之家收集整理的这篇文章主要介绍了c – 传递许多函数并将其所有结果存储在元组中前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
考虑这个输出
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
}

因此,多功能< 2,3>采用元组的前2个元素,并将它们传递给foo,接下来的元组3个元素,并将它们传递给bar等.我得到了这个工作(除了函数有重载,这是一个单独的问题).但是,所有函数的返回值都会丢失.我希望这些返回值存储在某个地方,像

std::tuple<int,bool> result = multiFunction<2,baz);

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

#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... 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...>&,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::index_sequence<>) {  // End of recursion.
        std::cout << std::boolalpha << oss.str();
        // Convert 'oss' into the desired tuple?  But how?
        return std::tuple<int,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,fs...);
}

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

int main() {
    const auto tuple = std::make_tuple(5,5.8);
    std::tuple<int,foo<bool>,baz<2,5,1>);  // foo<T>  bar  baz<int...>
}

解决方法

这里有一种方法,其中参数的数量贪婪地推导出来:
#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,typename ArgT,typename... Fs>
    constexpr auto call(index_sequence<Is...>,ArgT&&,Fs&&...);

    template <size_t offset,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,Fs&&... fs) {
        return call<offset>(index_sequence<Is...,sizeof...(Is)>{},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)...);}

Demo.但是,由于tuple_cat是递归调用的,所以上面的返回值的数量有二次时间复杂度.相反,我们可以使用稍微修改调用版本来获取每个调用的索引 – 然后直接获得实际的元组:

#include <tuple>

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

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

    template <typename ITuple,typename Args,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,Fs&&... fs) {
    return detail::apply_all<decltype(detail::indices<0>(std::index_sequence<>{},std::forward<Fs>(fs)...))>
             (std::forward<ArgT>(argt),std::index_sequence_for<Fs...>{},std::forward<Fs>(fs)...);}

Demo 2.

猜你在找的C&C++相关文章