Pass variadic std :: function - PullRequest
       45

Pass variadic std :: function

0 голосов
/ 10 октября 2018

У меня есть функция, которая принимает обратный вызов.Он должен работать с функциями ptrs, lambdas (без состояния и с состоянием) и т. Д. Я мог бы просто сделать следующее:

template<typename t_func>
void add_command(const std::string& name, t_func func)

Проблема в том, что мне нужно работать с типами аргументов func.Итак, я сделал это:

template<typename... t_args>
void add_command(const std::string& name, const std::function<void(t_args...)>& args)

Это создает следующую ошибку: no matching function for call to ...

note: template argument deduction/substitution failed

Есть ли способ передать универсальную функциютипа, все еще имея доступ к его аргументам?Я знаю о std::result_of, есть ли подобное std::arguments_of?

1 Ответ

0 голосов
/ 10 октября 2018

std::function является шаблоном стирания типа.Вывод типа - это противоположность (почти обратное) стиранию типа.

Вывод типа шаблона стирания типа - это запах кода.И это редко работает.

В есть руководство по вычетам, поэтому вы можете сделать:

template<typename... t_args>
void add_command(const std::string& name, const std::function<void(t_args...)>& args)        
void add_command(const std::string& name, t_func const& func) {
  std::function f = func;
  add_command(name, f);
}

это несовершенное, но идеальное решениеневозможно.

Руководства по выводу выглядят как :

template<class R, class... ArgTypes>
function(R(*)(ArgTypes...)) -> function<R(ArgTypes...)>;
template<class F>
function(F) -> function</*see below*/>;

, где извлекает подпись function посредством проверки &F::operator().Это может не сработать с перегрузками или шаблонами.И, естественно, это не работает с перегруженными именами функций.

Вы можете повторить это в с классом функций:

template<class X>
struct function_traits:function_traits<decltype(&X::operator())> {};
#define MEM_FUN_HELPER2(...) \
  template<class R, class T, class...Args> \
  struct function_traits<R(T::*)(Args...) __VA_ARGS__>:function_traits<R(Args...)>{}; \
  template<class R, class T, class...Args> \
  struct function_traits<R(T::*)(Args..., ...) __VA_ARGS__>:function_traits<R(Args..., ...)>{}; \
  template<class R, class T, class...Args> \
  struct function_traits<R(T::*)(Args...) __VA_ARGS__ noexcept>:function_traits<R(Args...) noexcept>{}; \
  template<class R, class T, class...Args> \
  struct function_traits<R(T::*)(Args..., ...) __VA_ARGS__  noexcept>:function_traits<R(Args..., ...) noexcept>{}
#define MEM_FUN_HELPER1(...) \
  MEM_FUN_HELPER2(__VA_ARGS__); \
  MEM_FUN_HELPER2(__VA_ARGS__ &); \
  MEM_FUN_HELPER2(__VA_ARGS__ &&)
#define MEM_FUN_HELPER0(...) \
  MEM_FUN_HELPER1(__VA_ARGS__); \
  MEM_FUN_HELPER1(const __VA_ARGS__)
#define MEM_FUN_HELPER() \
  MEM_FUN_HELPER0(); \
  MEM_FUN_HELPER0(volatile)

MEM_FUN_HELPER();

template<class R, class...Args>
struct function_traits<R(*)(Args...)>:function_traits<R(Args...)>{};
template<class R, class...Args>
struct function_traits<R(*)(Args..., ...)>:function_traits<R(Args..., ...)>{};
template<class R, class...Args>
struct function_traits<R(*)(Args...) noexcept>:function_traits<R(Args...) noexcept>{};
template<class R, class...Args>
struct function_traits<R(*)(Args..., ...) noexcept>:function_traits<R(Args..., ...) noexcept>{};
template<class R, class...Args>
struct function_traits<R(Args...) noexcept> : function_traits<R(Args...)> {
  enum {is_noexcept=true};
};
template<class R, class...Args>
struct function_traits<R(Args..., ...) noexcept> : function_traits<R(Args..., ...)> {
  enum {is_noexcept=true};
};
template<class R, class...Args>
struct function_traits<R(Args...)> {
  template<template<class...>class Z>
  using transcribe=Z<R(Args...)>;
  using std_function = transcribe<std::function>;
  using result_type = R;
  using arg_tuple = std::tuple<Args...>;
  enum{is_noexcept=false};
};
template<class R, class...Args>
struct function_traits<R(Args..., ...)> {
  template<template<class...>class Z>
  using transcribe=Z<R(Args..., ...)>;
  using std_function = transcribe<std::function>;
  using result_type = R;
  // doesn't really work, but what ya gonna do:
  using arg_tuple = std::tuple<Args...>;
  enum{is_noexcept=false};
};

что довольно безумно;MEM_FUN_HELPER(); расширяется до 48 шаблонных специализаций.3 квалификатора ref (&, && и ничего), затем 4 других элемента (const, volatile, noexcept и ... в стиле C), которые должны обрабатываться "вручную".

В любом случае, если у вас есть это, вы можете сделать:

template<typename... t_args>
void add_command(const std::string& name, const std::function<void(t_args...)>& args)        
template<class t_func>
void add_command(const std::string& name, t_func const& func) {
  typename function_traits<t_func>::std_function f = func;
  add_command(name, f);
}

в .Это (грубо и некорректно) делает то же самое, что и руководства по удержанию.

Живой пример .

...