使用 std::function 作为具有任意数量参数的数据成员

Using std::function as data member with arbitrary number of arguments

我正在尝试创建一个 class 并将 std::function 作为数据成员。

像这样:

template<typename ... Args>
using Function = std::function<void(Args...)>;

struct UI_Element
{
      std::shared_ptr<UI_Element> parent;
      std::vector<std::shared_ptr<UI_Element>> children;

      Function<> callbackFunc;

      template<typename F>
      void registerCallbackFunc(const F& f)
      {
               callbackFunc = f;
      }

      template<typename ... Args>
      void doFunc(Args&& ... args)
      {
             callbackFunc(std::forward<Args>(args)...);
      }
};

问题是它显然适用于不接受任何参数的函数(由于 Function<>)。例如,

void doStuff() 
{
      std::cout << "This function works\n";
}

有没有办法让我注册包含任意数量参数的回调函数?

或者其他方式,而不使用 std::function 来实现我想要的?

具有不同参数列表的每个 std::function 都是一个单独的 class。由于一个成员只能具有一种类型,因此实现此目的的唯一方法是隐藏该类型。

因此,这在技术上可以通过将函数包装器存储在 std::any 中来实现。也许可以编写一个更具体的 "any-function" 包装器,但遵循 "works":

std::any callbackFunc;

template<typename ... Args>
void registerCallbackFunc(std::function<void(Args...)> f)
{
    callbackFunc = std::function(f);
}

template<typename ... Args>
void doFunc(Args ... args)
{
    std::any_cast<std::function<void(Args...)>>(callbackFunc)(std::move(args)...);
}

这不是很好处理。引用参数是不允许的(强制未实现)并且您必须传递具有完全正确类型的参数,因为隐式转换不能通过此接口工作。所以,如果你注册了void(int),你就不能用void(long)调用它了。

如果您尝试使用错误数量的参数调用,将抛出异常。

我的结论:没有简单的解决方案可以将具有无约束参数列表的函数存储到单一类型中。这种尝试对于一般用途来说肯定是不够的。