可变参数函数包装器,用于任何返回类型

时间:2019-03-29 15:14:19

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

我正在尝试编写可变参数模板包装程序,以将任何函数传递给它,并且(可能)要返回其返回值。

现在我想出了下面的代码,但我真的很讨厌我需要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)...);
}

有什么办法可以消除其中的一些重载?事实证明,这种方法可以很好地工作,但是从代码方面来说,我真的希望更短一些。

1 个答案:

答案 0 :(得分: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)...);
}