Я намереваюсь реализовать шаблонную функцию, которая будет принимать две функции и список их параметров, а затем создаст две оболочки. Я уже реализовал подобное решение, чтобы принять две функции и создать оболочку, используя std::bind(), но используя жестко заданные параметры. Решение примерно так:

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

Как видите, параметры std::bind() жестко запрограммированы в обоих случаях, и я хотел бы прочитать их через функцию myWrapper(). Есть ли способ прочитать два шаблона переменных (список переменных произвольной длины и типа) и отправить их на два std::bind() вызова, которые у меня есть в приведенном выше коде?

Спасибо

Дэн

0
Dan 19 Окт 2017 в 11:49

3 ответа

Лучший ответ

Не уверен, что понимаю, что вы хотите, но я полагаю, вам нужно использовать std::tuple (или что-то похожее) для разделения двух последовательностей аргументов.

Ниже приводится полный рабочий пример того, что я имею в виду, согласно тому, что я понимаю, что вы хотите.

#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
 }

К сожалению, это код C ++ 14 (auto возвращаемый тип; std::index_sequence и std::make_index_sequence), но его легко адаптировать в C ++ 11.

- РЕДАКТИРОВАТЬ -

Как указал Банан (спасибо!), Нет необходимости явно указывать тип возвращаемых функций (T1, T2).

Используя тип возврата auto, пример можно упростить следующим образом

#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
 }
2
max66 19 Окт 2017 в 13:03

Что касается вашего представления о variadicStruct, возможно, вы захотите взглянуть на {{ X1 } }.

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

Чтобы называться так:

do_stuff(std::make_tuple(4.7, 'x', 1.0, 4, 8l), std::make_tuple("foo", 1));
2
Julius 19 Окт 2017 в 10:47

Вы можете использовать std::make_tuple и std::apply, например:

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 требует поддержки C ++ 17. Однако связанная страница на cppreference содержит возможную реализацию, которая работает в C + +11 .

1
lisyarus 19 Окт 2017 в 12:00