Variadi c Расширение параметров шаблона внутри члена класса типа std :: function - PullRequest
0 голосов
/ 27 января 2020

У меня есть класс под названием «Меню», который используется для отображения параметров, которые пользователь может выбрать. Затем пользователь выбирает параметр, и это значение обрабатывается. Тем не менее, у меня есть дочерний класс, который ничего не отображает, а просто принимает std :: function с переменным числом аргументов.

Подпись выглядит как

template<class FuncRetTy, class... FuncArgs>
class FunctionMenu : public Menu;

В идеале Я хотел бы сохранить член класса, который имеет форму:

std::function<FuncRetTy(FuncArgs...)> m_function;

Я также хотел бы автоматически выводить все типы из конструктора и сохранять значения FuncArgs..., чтобы эти значения могли быть запускать эту функцию каждый раз при вызове переопределенного метода "run()". Внутри run(), m_function(/* FuncArgs values */) будет называться.

Любые идеи приветствуются. Я использую Visual Studio 2019 с C ++ 17.

Ответы [ 2 ]

0 голосов
/ 27 января 2020

Самый простой способ - использовать std::bind для хранения аргументов.

#include <functional>

template <typename Ret>
class FunctionMenu {
 public:
  template <typename Ret, typename... Args>
  explicit FunctionMenu(std::function<Ret(Args...)> func, Args... args)
      : m_function{std::bind(func, std::move(args)...)} {}

  auto run() { return m_function(); }

 private:
  std::function<Ret()> m_function;
};

template <typename Ret, typename... Args>
FunctionMenu(std::function<Ret(Args...)>, Args...)->FunctionMenu<Ret>;

Таким образом, аргументы хранятся внутри std::function. Также возможно сохранить аргументы вручную в std::tuple и распаковать их при вызове run().

#include <tuple>

template <typename Ret, typename... Args>
class FunctionMenu2 {
 public:
  template <typename Ret, typename... Args>
  explicit FunctionMenu2(std::function<Ret(Args...)> func, Args... args)
      : m_function{func}, m_args{std::move(args)...} {}

  auto run() { return std::apply(m_function, m_args); }

 private:
  std::function<Ret(Args...)> m_function;
  std::tuple<Args...> m_args;
};

template <typename Ret, typename... Args>
FunctionMenu2(std::function<Ret(Args...)>, Args...)
    ->FunctionMenu2<Ret, Args...>;

Второй подход позволяет вам легче получить доступ к аргументам (если требуется). Вот как использовать оба класса:

int main() {
  std::function<int(float, int)> f = [](auto a, auto b) {
    std::cout << a << std::endl;
    std::cout << b << std::endl;
    return 0;
  };

  FunctionMenu menu(f, 1.f, 200);
  FunctionMenu2 menu2(f, 1.f, 200);

  std::cout << menu.run() << std::endl;
  std::cout << menu2.run() << std::endl;

  return 0;
}
0 голосов
/ 27 января 2020

Это то, что вы хотите?

#include <functional>
#include <iostream>

template<class Ret, class... Args>
class FunctionMenu {
    std::function<Ret(Args...)> m_function;

  public:
    FunctionMenu(std::function<Ret(Args...)> f) : m_function(f) {}

    Ret run(Args... args) {
        return f(args...);
    }
};

template<class Ret, class... Args>
FunctionMenu(std::function<Ret(Args...)>)->FunctionMenu<Ret, Args...>;

int test(int i, double d) {
    std::cout << i << ' ' << d << '\n';
    return 0;
}

int main() {
    std::function m = test;

    FunctionMenu fm{m};
}

(я не добавил базовый класс Menu, так как он не показался релевантным)

...