【问题标题】:Variadic function wrapper for any return type任何返回类型的可变参数函数包装器
【发布时间】:2019-03-29 15:14:19
【问题描述】:

我正在尝试为要传递给它的任何函数编写一个可变参数模板包装器,并且(可能)它是要返回的返回值。

现在我想出了下面的代码,但我真的很讨厌我需要 6 个不同的函数重载,3 个用于 void 返回类型,3 个用于非 void 返回类型。

// Void return type
// Template for non-member functions
template <typename Callable, typename... Args>
std::enable_if_t<std::is_void<std::result_of_t<Callable(Args...)> >::value
    && std::is_member_function_pointer<Callable>::value == false>
call(Callable worker, Args... params)
{
    worker(std::forward<Args>(params)...);
}

// Template for member functions (general)
template <typename Callable, typename... Args>
std::enable_if_t<std::is_void<std::result_of_t<Callable(Args...)> >::value
    && std::is_member_function_pointer<Callable>::value>
call(Callable worker, Args... params)
{
    call(std::forward<Callable>(worker), std::forward<Args>(params)...);
}

// Template for member functions (object instance extractor)
template <typename Callable, typename Object, typename... Args>
std::enable_if_t<std::is_void<std::result_of_t<Callable(Args...)> >::value
    && std::is_member_function_pointer<Callable>::value>
call(Callable worker, Object object, Args... params)
{
    auto fn = std::mem_fn(worker);
    fn(std::forward<Object>(object), std::forward<Args>(params)...);
}

// Non-void return types
// Template for non-member functions
template <typename Callable, typename... Args>
std::enable_if_t<std::is_void<std::result_of_t<Callable(Args...)> >::value == false
    && std::is_member_function_pointer<Callable>::value == false
    , std::result_of_t<Callable(Args...)> >
call(Callable worker, Args... params)
{
    return worker(std::forward<Args>(params)...);
}

// Template for member functions (general)
template <typename Callable, typename... Args>
std::enable_if_t<std::is_void<std::result_of_t<Callable(Args...)> >::value == false
    && std::is_member_function_pointer<Callable>::value
    , std::result_of_t<Callable(Args...)> >
call(Callable worker, Args... params)
{
    return call(std::forward<Callable>(worker), std::forward<Args>(params)...);
}

// Template for member functions (object instance extractor)
template <typename Callable, typename Object, typename... Args>
std::enable_if_t<std::is_void<std::result_of_t<Callable(Args...)> >::value == false
    && std::is_member_function_pointer<Callable>::value
    , std::result_of_t<Callable(Args...)> >
call(Callable worker, Object object, Args... params)
{
    auto fn = std::mem_fn(worker);
    return fn(std::forward<Object>(object), std::forward<Args>(params)...);
}

有什么办法可以摆脱这些重载?事实证明,这种方法效果很好,但在代码方面我真的想要一些更短的东西。

【问题讨论】:

  • 你仅限于 C++14 吗? C++17 提供了std::invoke,它就是这样做的。
  • 此外,在返回 void 的函数中执行 return void_returning_function(); 是合法的,因此对于 void 函数您真的不需要特殊情况。
  • @NathanOliver,不幸的是,现在我仅限于 C++14,所以std::invoke 是不行的。那是我的第一次。至于return void_returning_function();,我不记得了,谢谢!

标签: c++ templates c++14 variadic-templates


【解决方案1】:

这是一个带有 SFINAE 的较短版本(如果不需要,可以用 decltype(auto) 代替)。

template <typename R, typename T, typename... Args, typename U,
          typename... Params>
auto call(R (T::*arg)(Args...), U &&first, Params &&... params)
    -> decltype((std::forward<T>(first).*
                 arg)(std::forward<Params>(params)...)) {
  return (std::forward<T>(first).*arg)(std::forward<Params>(params)...);
}

template <typename F, typename... Ts>
auto call(F &&f, Ts &&... args)
    -> decltype(std::forward<F>(f)(std::forward<Ts>(args)...)) {
  return std::forward<F>(f)(std::forward<Ts>(args)...);
}

【讨论】:

  • 这看起来不错,但是当我尝试这样使用它时,出现编译错误:class Foo { int bar(int, int*); } foo; int *i = new int; call(&amp;Foo::bar, foo, 1, a); 基本上,我收到错误:no matching function for call to 'forward(Foo*&amp;)' -&gt; decltype((std::forward&lt;T&gt;(first).*arg)(std::forward&lt;Params&gt;(params)...)) 也许我做错了什么?
  • @Theoden91 如果您将i 更改为a 并使用struct(因为bar 是私有的),它对我有用。
  • 你是对的。我在代码中发现了错误。非常感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2021-10-06
  • 2018-07-08
  • 2018-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-01
  • 1970-01-01
相关资源
最近更新 更多