如何包装 std::function 并轻松访问其 return 和参数类型?

How can I wrap a std::function and have easy access to its return and argument types?

我正在尝试做一些可以简化为以下内容的事情:

#include <functional>
#include <initializer_list>
#include <vector>

template <typename Ret, typename... Args>
struct func_wrapper
{
public:
    using Func = std::function<Ret(Args...)>;

    Ret operator()(Args && ...args)
    {
        return _impl(std::forward<Args>(args)...);
    }

    void another_function(int another_arg, Args && ...args) { }
    /// and so on

private:
   Func _impl;
};

func_wrapper<void(int, float)> f;


基本上,我想创建一个包装 std::function 的类型并为我的应用程序添加一些其他功能。在我的类型中,我希望能够在 class 接口中自由使用 return 类型 Ret 和自变量参数包 Args。但是,when I try to compile the above with gcc 8.3, I get an error:

<source>: In instantiation of 'struct func_wrapper<void(int, float)>':
<source>:20:32:   required from here
<source>:9:45: error: function returning a function
     using Func = std::function<Ret(Args...)>;
                                             ^
<source>:11:9: error: function returning a function
     Ret operator()(Args && ...args)

我不确定该错误是怎么回事。有没有一种简单的方法可以做我想做的事?

问题是你必须使用偏特化

template <typename>
struct func_wrapper;

template <typename Ret, typename... Args>
struct func_wrapper<Ret(Args...)>
 {
   // ...
 };

如果你写

template <typename Ret, typename... Args>
struct func_wrapper
 {
   // ...
 };

声明 f

func_wrapper<void(int, float)> f;

您将 Ret 推导为 void(int, float),将 Args... 可变参数列表推导为空列表。

所以,当你定义

using Func = std::function<Ret(Args...)>;

Func声明变为

// ............................V..........VVV  function-function type ?
using Func = std::function<void(int, float)()>;

给出 "error: function returning a function" 错误。

您必须将 func_wrapper 声明为接收单个类型名称

template <typename>
struct func_wrapper;

所以你可以传递函数的类型(void(int, float)在你的例子中)作为模板参数,然后是模板特化

template <typename Ret, typename... Args>
struct func_wrapper<Ret(Args...)>
 {
   // ...
 };

可以从函数类型解析 return 类型和参数类型。

@max66 的回答很好地展示了如何避免您 运行 遇到的问题。有关此处具体不起作用的更多信息,请查看您如何参数化模板以及如何使用它:

template <typename Ret, typename... Args> struct func_wrapper {
     ...
};

这意味着您的模板希望您通过编写类似

的内容来实例化它
func_wrapper<int, float> // Function taking a float and returning an int
func_wrapper<void, int, float> // Function taking a float and an int and returning void
func_wrapper<int> // Function taking no arguments and returning void

请特别注意,func_wrapper<T> 意味着 Ret 将是 T 并且该函数将不带任何参数。

因此,当你写

func_wrapper<void(int, float)>

你说的 "a function representing something that takes no arguments and returns a function that takes in an int and a float and returns void," 这不是你想要的。这就是为什么您会收到有关返回非法函数的错误。