考虑这个输出:
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)...);}