简体   繁体   中英

Function with two variadic parameters

I intend to implement a template function which would accept two functions and their parameters list and then created two wrappers. I have already implemented similar solution to accept two function and create wrapper using std::bind() but using hard-coded parameters. The solution is something like this:

template <typename T1, typename T2, typename T3, typename T4>
myWrapper (T2 func1, T4 func2) {
  std::function<T1>ff = std::bind(func1, 1, placeholders::_1);
  std::function<T3>ff = std::bind(func1, 110, 20, "something");
}

As you see the parameters to std::bind() are hard-coded in both cases which I would like to read them through myWrapper() function. Is there any way to read two variadic templates (list of variables of arbitrary length and type) and send them to two std::bind() calls I have in the above code?

Thanks,

Dan

Regarding your idea of a variadicStruct you may wish to have a look at std::tuple .

template<class... Ts, class... Us>
void do_stuff(const std::tuple<Ts...>&, const std::tuple<Us...>&) {
  std::cout << "two variadic packs with " << sizeof...(Ts)
        << " and " << sizeof...(Us) << " elements." << std::endl;
}

To be called like this:

do_stuff(std::make_tuple(4.7, 'x', 1.0, 4, 8l), std::make_tuple("foo", 1));

Not sure to understand what you want but I suppose you need to use std::tuple (or something similar) to separate the two sequences of args.

The following is an full working example of what I mean, according what I've understand of what do you want.

#include <tuple>
#include <string>
#include <utility>
#include <iostream>
#include <functional>

template <typename T1, typename T2, typename T3, typename T4,
          typename ... Ts1, typename ... Ts2,
          std::size_t ... Is1, std::size_t ... Is2>
auto myWrapperH (T3 func1, T4 func2, std::tuple<Ts1...> const & tp1,
                 std::tuple<Ts2...> const & tp2,
                 std::index_sequence<Is1...> const &,
                 std::index_sequence<Is2...> const &)
 {
   T1 f1 = std::bind(func1, std::get<Is1>(tp1)...);
   T2 f2 = std::bind(func2, std::get<Is2>(tp2)...);

   return std::make_pair(f1, f2);
 }

template <typename T1, typename T2, typename T3, typename T4,
          typename ... Ts1, typename ... Ts2>
auto myWrapper (T3 func1, T4 func2, std::tuple<Ts1...> const & tp1,
                std::tuple<Ts2...> const & tp2)
 { return myWrapperH<T1, T2>(func1, func2, tp1, tp2,
                             std::make_index_sequence<sizeof...(Ts1)>{},
                             std::make_index_sequence<sizeof...(Ts2)>{}); }

int foo (int a, int b)
 { return a+b; }

std::size_t bar (int a, int b, std::string const & str)
 { return str.size() + a + b; }

int main ()
 {
   using fType1 = std::function<int(int)>;
   using fType2 = std::function<long()>;

   auto mwr = myWrapper<fType1, fType2>(&foo, &bar,
                 std::make_tuple(1, std::placeholders::_1),
                 std::make_tuple(110, 20, std::string{"something"}));

   std::cout << mwr.first(5) << std::endl; // print   6
   std::cout << mwr.second() << std::endl; // print 139
 }

Unfortunately is a C++14 code ( auto return type; std::index_sequence and std::make_index_sequence ) but should be easy to adapt in C++11.

-- EDIT --

As pointed by Banan (thanks!) there is no need to explicit the type of returned functions ( T1 , T2 ).

Using the auto return type the example can be simplified as follows

#include <tuple>
#include <string>
#include <utility>
#include <iostream>
#include <functional>

template <typename F1, typename F2, typename ... Ts1, typename ... Ts2,
          std::size_t ... Is1, std::size_t ... Is2>
auto myWrapperH (F1 func1, F2 func2, std::tuple<Ts1...> const & tp1,
                 std::tuple<Ts2...> const & tp2,
                 std::index_sequence<Is1...> const &,
                 std::index_sequence<Is2...> const &)
 { return std::make_pair(std::bind(func1, std::get<Is1>(tp1)...),
                         std::bind(func2, std::get<Is2>(tp2)...)); }

template <typename F1, typename F2, typename ... Ts1, typename ... Ts2>
auto myWrapper (F1 func1, F2 func2, std::tuple<Ts1...> const & tp1,
                std::tuple<Ts2...> const & tp2)
 { return myWrapperH(func1, func2, tp1, tp2,
                     std::make_index_sequence<sizeof...(Ts1)>{},
                     std::make_index_sequence<sizeof...(Ts2)>{}); }

int foo (int a, int b)
 { return a+b; }

std::size_t bar (int a, int b, std::string const & str)
 { return str.size() + a + b; }

int main ()
 {
   auto mwr = myWrapper(&foo, &bar,
                 std::make_tuple(1, std::placeholders::_1),
                 std::make_tuple(110, 20, std::string{"something"}));

   std::cout << mwr.first(5) << std::endl; // print   6
   std::cout << mwr.second() << std::endl; // print 139
 }

You can use std::make_tuple and std::apply , for example:

template <typename R, typename Func1, typename Args1>
void wrapper (Func1 f1, Args1 a1)
{
    std::function<R> wrapped1 = [f1, a1]{ return std::apply(f1, a1); };
}

// ...

auto deg_to_rad = [](int x){ return x / 180.f * 3.1415f; };
wrapper<float>(deg_to_rad, std::make_tuple(45));

std::apply requires C++17 support. However, the linked page on cppreference contains a possible implementation that works in C++11.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM