微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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.

原文地址:https://www.jb51.cc/c/113229.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐