2016-03-18 21 views
10

考虑这个输出:传递许多功能和存储在元组的所有结果

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 
} 

所以multiFunction<2,3,3>需要的tuple第一2个元素并将它们传递给foo,的tuple接下来的3个元素并将它们传递给bar等...我得到了这个工作(除非函数有重载,这是一个单独的问题)。但是所调用的每个函数的返回值都丢失了。我想这些返回值存储在某处,像

std::tuple<int, double, bool> result = multiFunction<2,3,3> (tuple, foo, bar, 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 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...> 
} 
+2

只需更改'functionOnTuple'来返回单元素'元组'。对于'void',返回一个'tuple <>'(或者'tuple ')。然后你可以把它们tuple_cat一起。显然,这不是最有效的,但其余的代码都不是。 –

+0

这个问题的解决方案是有趣和信息丰富的,但我很难理解'multicall'是最优雅的解决方案。这似乎有点......不可维护? –

+0

@Richard Hodges有一天可能会派上用场的另一个层面。 – prestokeys

回答

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)...);} 

Demo。但是,由于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)...);} 

Demo 2

+3

是的!没有水平滚动条! – Columbo

+0

是的,你总是给出最短的解决方案。但GCC 5.2抱怨无效的右值初始化(小事)。 – prestokeys

+0

是否有任何机会允许具有重载的传递函数? – prestokeys

4

从头开始构建并忽略完美的转发,因此我必须输入较少。我们需要一些帮手。首先,我们需要一个部分版本的应用是需要从我们要应用到该函数的元组指数:

<class Tuple, class F, size_t... Is> 
auto partial_apply(Tuple tuple, F f, std::index_sequence<Is...>) { 
    return f(get<Is>(tuple)...); 
} 

然后,我们需要调用该函数的元组的每个子集。比方说,我们有我们所有的功能和指标包裹在一个元组已经:

template <class Tuple, class FsTuple, class IsTuple, size_t... Is> 
auto multi_apply(Tuple tuple, FsTuple fs, IsTuple indexes, std::index_sequence<Is...>) { 
    return std::make_tuple(
     partial_apply(tuple, 
      std::get<Is>(fs), 
      std::get<Is>(indexes) 
      )... 
     ); 
} 

所以在这种情况下,我们会想最终调用multi_apply(tuple, <foo,bar,baz>, <<0,1>,<2,3,4>,<5,6,7>>, <0, 1, 2>)

我们所需要知道的是构建indexes部分。我们从<2,3,3>开始。我们需要得到部分和(<0,2,5>)并将其添加到索引序列<<0,1>,<0,1,2>,<0,1,2>>。因此,我们可以写一个部分和功能:

template <size_t I> 
using size_t_ = std::integral_constant<size_t, I>; 

template <class R, size_t N> 
R partial_sum_(std::index_sequence<>, R, size_t_<N>) { 
    return R{}; 
} 

template <size_t I, size_t... Is, size_t... Js, size_t S> 
auto partial_sum_(std::index_sequence<I, Is...>, 
     std::index_sequence<Js...>, size_t_<S>) 
{ 
    return partial_sum_(std::index_sequence<Is...>{}, 
     std::index_sequence<Js..., S>{}, size_t_<S+I>{}); 
} 

template <size_t... Is> 
auto partial_sum_(std::index_sequence<Is...> is) 
{ 
    return partial_sum_(is, std::index_sequence<>{}, size_t_<0>{}); 
}; 

我们可以用它来产生我们所有的指标作为一个元组:

template <size_t... Is, size_t N> 
auto increment(std::index_sequence<Is...>, size_t_<N>) 
{ 
    return std::index_sequence<Is+N...>{}; 
} 

template <class... Seqs, size_t... Ns> 
auto make_all_indexes(std::index_sequence<Ns...>, Seqs... seqs) 
{ 
    return std::make_tuple(increment(seqs, size_t_<Ns>{})...); 
} 

像这样:

template <size_t... Is, class Tuple, class... Fs> 
auto multiFunction(Tuple tuple, Fs... fs) 
{ 
    static_assert(sizeof...(Is) == sizeof...(Fs)); 
    return multi_apply(tuple, 
     std::make_tuple(fs...), 
     make_all_indexes(
      partial_sum_(std::index_sequence<Is...>{}), 
      std::make_index_sequence<Is>{}... 
      ), 
     std::make_index_sequence<sizeof...(Is)>{} 
     ); 

} 

如果你想处理void返回,那么就让partial_apply返回一个元素的元组(或者一个空tu ple)并将multi_apply中的make_tuple()用法更改为tuple_cat()

+0

@巴里我写了另一个解决方案,我认为遵循你的思路,使用部分和:http://ideone.com/Rl8KKo我们都在最后使用'std :: make_tuple'返回行,但'std :: make_tuple'显然以正确的顺序输出值,但以相反的顺序调用函数。 – prestokeys

+0

@prestokeys函数参数的评估顺序未指定。 – Barry

+0

@ Barry你是对的。我忘了说明这一点。在这个程序中应该从左到右阅读这些功能(可能很重要)。我不明白'std :: make_tuple'的实现是如何以相反顺序调用函数的。看起来我们必须编写我们自己的make_tuple函数来确保函数的从左到右。 – prestokeys

2

这里的另一个IMPL:

template<std::size_t N> 
constexpr Array<std::size_t, N> scan(std::size_t const (&a)[N]) 
{ 
    Array<std::size_t, N> b{}; 
    for (int i = 0; i != N - 1; ++i) 
     b[i + 1] = a[i] + b[i]; 
    return b; 
} 

template<std::size_t O, std::size_t... N, class F, class Tuple> 
inline decltype(auto) eval_from(std::index_sequence<N...>, F f, Tuple&& t) 
{ 
    return f(std::get<N + O>(std::forward<Tuple>(t))...); 
} 

template<std::size_t... O, std::size_t... N, class Tuple, class... F> 
inline auto multi_function_impl1(std::index_sequence<O...>, std::index_sequence<N...>, Tuple&& t, F... f) 
{ 
    return pack(eval_from<O>(std::make_index_sequence<N>(), f, std::forward<Tuple>(t))...); 
} 

template<std::size_t... I, std::size_t... N, class Tuple, class... F> 
inline auto multi_function_impl0(std::index_sequence<I...>, std::index_sequence<N...>, Tuple&& t, F... f) 
{ 
    constexpr std::size_t ns[] = {N...}; 
    constexpr auto offsets = scan(ns); 
    return multi_function_impl1(std::index_sequence<offsets[I]...>(), std::index_sequence<N...>(), std::forward<Tuple>(t), f...); 
} 

template<std::size_t... N, class Tuple, class... F> 
auto multi_function(Tuple&& t, F... f) 
{ 
    return multi_function_impl0(std::make_index_sequence<sizeof...(N)>(), std::index_sequence<N...>(), std::forward<Tuple>(t), f...); 
} 

其中packArray分别类似于std::make_tuplestd::array,但要克服一些问题:

  • std::make_tuple衰减它指定参数时,这样的引用都将丢失
  • std::array不能在C++中使用constexpr编写它的元素14

DEMO

2

这个解决方案应该具有线性时间复杂度。它使用std::tie而不是std::make_tuple,所以函数和参数都不必要的复制。我认为跟这里的其他答案相比应该相当容易。

首先,我们需要一个实用程序来调用一个使用参数std::tuple的函数。

template <typename F, typename Args, std::size_t... Is> 
auto invoke_impl(F const& f, Args const& args, std::index_sequence<Is...>) 
{ 
    return f(std::get<Is>(args)...); 
} 

template <typename F, typename Args> 
auto invoke(F const& f, Args const& args) 
{ 
    return invoke_impl(f, args, std::make_index_sequence<std::tuple_size<Args>::value>()); 
} 

其次,我们需要一个工具来std::tie元组元素的子范围。

template <std::size_t Offset, typename Tuple, std::size_t... Is> 
auto sub_tie_impl(Tuple const& tuple, std::index_sequence<Is...>) 
{ 
    return std::tie(std::get<Offset + Is>(tuple)...); 
} 

template <std::size_t Offset, std::size_t Count, typename Tuple> 
auto sub_tie(Tuple const& tuple) 
{ 
    return sub_tie_impl<Offset>(tuple, std::make_index_sequence<Count>()); 
} 

现在我们可以创建我们的实用程序来使用一系列函数来消费参数std::tuple

首先我们将std::tie函数转换为一个元组,然后我们将参数列表分成一个子参数列表的参数包,最后我们为每个子参数列表调用一个函数,将结果打包成一个元组,然后返回。

template <typename Fs, std::size_t... Is, typename... SubArgs> 
auto consume_impl(Fs const& fs, std::index_sequence<Is...>, SubArgs const&... sub_args) 
{ 
    return std::make_tuple(invoke(std::get<Is>(fs), sub_args)...); 
} 

template <std::size_t, typename Args, typename Fs, typename... SubArgs> 
auto consume_impl(Args const&, Fs const& fs, SubArgs const&... sub_args) 
{ 
    return consume_impl(fs, std::make_index_sequence<sizeof...(SubArgs)>(), sub_args...); 
} 

template <std::size_t Offset, std::size_t Count, std::size_t... Counts, 
      typename Args, typename Fs, typename... SubArgs> 
auto consume_impl(Args const& args, Fs const& fs, SubArgs const&... sub_args) 
{ 
    return consume_impl<Offset + Count, Counts...>(args, fs, sub_args..., 
                sub_tie<Offset, Count>(args)); 
} 

template <std::size_t... Counts, typename Args, typename... Fs> 
auto consume(Args const& args, Fs const&... fs) 
{ 
    return consume_impl<0, Counts...>(args, std::tie(fs...)); 
} 
2

这里有以下TC的意见后,我的解决方案,增加了我以前的(虽然效率不高)的解决方案:

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

struct NoReturnValue { 
    friend std::ostream& operator<< (std::ostream& os, const NoReturnValue&) { 
     return os << "[no value returned]"; 
    } 
}; 

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...>&, 
     std::enable_if_t< !std::is_void<std::result_of_t<F(std::tuple_element_t<Is, Tuple>...)>>::value >* = nullptr) { // This overload is called only if f's return type is not void. 
    return std::make_tuple(f(std::get<Is>(tuple)...)); // Thanks to T.C.'s advice on returning a single tuple and then calling std::tuple_cat on all the single tuples. 
} 

template <typename Tuple, typename F, std::size_t... Is> 
auto functionOnTupleHelper (const Tuple& tuple, F f, const std::index_sequence<Is...>&, 
     std::enable_if_t< std::is_void<std::result_of_t<F(std::tuple_element_t<Is, Tuple>...)>>::value >* = nullptr) { // This overload is called only if f's return type is void. 
    f(std::get<Is>(tuple)...); 
    return std::tuple<NoReturnValue>(); // Thanks to T.C.'s advice on returning std::tuple<NoReturnValue>() if the return type of 'f' is void. 
} 

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, 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); 
     const auto r = functionOnTuple(headTuple, f); // Which overload of 'functionOnTupleHelper' is called dedends on whether f's return type is void or not. 
     return std::tuple_cat (r, MultiFunction<std::remove_const_t<decltype(tailTuple)>, Fs...>::execute (tailTuple, std::index_sequence<Is...>{}, fs...)); // T.C.'s idea of tuple_cat with all the single return tuples. 
    } 
}; 

template <> 
struct MultiFunction<std::tuple<>> { 
    static auto execute (const std::tuple<>&, std::index_sequence<>) { return std::tuple<>(); } 
}; 

template <std::size_t... Is, typename Tuple, typename... Fs> 
auto multiFunction (const Tuple& tuple, Fs... fs) { 
    return MultiFunction<Tuple, Fs...>::execute (tuple, 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;} 
double bar (bool, int) {return 1.4;} 
void voidFunction() {std::cout << "voidFunction\n";} 
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); 
    const auto firstBar = [](bool b, double d, long l) {return bar(b, d, l);}; 
    const auto t = multiFunction<2,3,0,3> (tuple, foo<bool>, firstBar, voidFunction, baz<2,5,1>); // Note that since 'bar' has an overload, we have to define 'firstBar' to indicate which 'bar' function we want to use. 
    std::cout << std::boolalpha << std::get<0>(t) << ' ' << std::get<1>(t) << ' ' << std::get<2>(t) << ' ' << std::get<3>(t) << '\n'; 
    // 0 3.5 [no value returned] true 
} 
0

这里的另一种解决方案借款巴里的partial_apply想法,但避免使用他的partial_sum功能的共。因此结果更短。我认为这在时间复杂度上是线性的。

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

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

template <typename Off, typename F, typename Tuple> // Off must be of type OffsetIndexSequence<A,B> only. 
auto partial_apply (F f, const Tuple& tuple) { 
    return partial_apply_impl<Off::value>(f, tuple, typename Off::sequence{}); 
} 

template <std::size_t Offset, std::size_t Size> 
struct OffsetIndexSequence : std::integral_constant<std::size_t, Offset> { 
    using sequence = std::make_index_sequence<Size>; 
}; 

template <typename Output, std::size_t... Is> struct OffsetIndexSequenceBuilder; 

template <template <typename...> class P, typename... Out, std::size_t Offset, std::size_t First, std::size_t... Rest> 
struct OffsetIndexSequenceBuilder<P<Out...>, Offset, First, Rest...> : 
    OffsetIndexSequenceBuilder<P<Out..., OffsetIndexSequence<Offset, First>>, Offset + First, Rest...> {}; 

template <template <typename...> class P, typename... Out, std::size_t Offset> 
struct OffsetIndexSequenceBuilder<P<Out...>, Offset> { 
    using type = P<Out...>; 
}; 

template <std::size_t... Is> 
using offset_index_sequences = typename OffsetIndexSequenceBuilder<std::tuple<>, 0, Is...>::type; 

template <typename> struct MultiFunction; 

template <template <typename...> class P, typename... Offs> 
struct MultiFunction<P<Offs...>> { 
    template <typename ArgsTuple, typename... Fs> 
    static auto execute (const ArgsTuple& argsTuple, Fs... fs) { 
     using ResultTuple = std::tuple<decltype(partial_apply<Offs>(fs, argsTuple))...>; 
     return ResultTuple{partial_apply<Offs>(fs, argsTuple)...}; 
    } 
}; 

template <std::size_t... Is, typename ArgsTuple, typename... Fs> 
auto multiFunction (const ArgsTuple& argsTuple, Fs... fs) { 
    return MultiFunction<offset_index_sequences<Is...>>::execute(argsTuple, fs...); 
} 

// Testing 
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); 
    const std::tuple<int, double, bool> t = multiFunction<2,3,3> (tuple, foo, bar, baz); // foo bar baz 
    std::cout << std::boolalpha << std::get<0>(t) << ' ' << std::get<1>(t) << ' ' << std::get<2>(t) << '\n'; // 0 3.5 true 
}