存储函数及其(任意类型,任意数)参数的简洁方法

JKS*_*KSH 5 c++ variadic c++11

对于一个库,我想要一个接受另一个函数及其参数的函数,然后将它们存储起来以便以后调用.参数必须允许任何类型的混合,但函数只需要返回void.像这样的东西:

void myFunc1(int arg1, float arg2);
void myFunc2(const char *arg1);
class DelayedCaller
{ ...
public:
    static DelayedCaller *setup(Function func, …);
};

...
DelayedCaller* caller1 = DelayedCaller::setup(&myFunc1, 123, 45.6);
DelayedCaller* caller2 = DelayedCaller::setup(&myFunc2, "A string");

caller1->call(); // Calls myFunc1(), with arguments 123 and 45.6
caller2->call(); // Calls myFunc2(), with argument "A string"
Run Code Online (Sandbox Code Playgroud)

一种方法是让DelayedCaller :: setup()接受一个std :: function,让我的库用户在调用setup()之前使用std :: bind().但是,有没有办法实现setup(),以便用户不需要自己进行绑定?

编辑:DelayedCaller是一个现有的类.setup()是一个我想添加的新静态方法.

Fer*_*cio 7

您可以使用lambda函数来隐藏绑定:

#include <functional>

class DelayedCaller : public std::function< void(void) > {
public:
    DelayedCaller(std::function< void(void) > fn)
      : std::function< void(void) >(fn) {}
};

DelayedCaller caller1([]() { myFunc1(123, 45.6); });
DelayedCaller caller2([]() { myFunc2("A string"); });

caller1(); // Calls myFunc1(), with arguments 123 and 45.6
caller2(); // Calls myFunc2(), with argument "A string"
Run Code Online (Sandbox Code Playgroud)

这也为您图书馆的用户提供了更大的灵活性.它们不仅限于单个函数调用,并且函数可以访问它们在以下位置创建的原始环境:

int x;

DelayedCaller caller3 = [&x]() {
    if (x == 0)
        DoSomething();
    else
        DoSomethingElse();
};
Run Code Online (Sandbox Code Playgroud)


hmj*_*mjd 7

一种可能性是使用可变参数模板并std::bind()setup()函数内调用:

#include <iostream>
#include <string>
#include <functional>
#include <memory>

void myFunc1(int arg1, float arg2)
{
    std::cout << arg1 << ", " << arg2 << '\n';
}
void myFunc2(const char *arg1)
{
    std::cout << arg1 << '\n';
}

class DelayedCaller
{
public:
    template <typename TFunction, typename... TArgs>
    static std::unique_ptr<DelayedCaller> setup(TFunction&& a_func,
                                                TArgs&&... a_args)
    {
        return std::unique_ptr<DelayedCaller>(new DelayedCaller(
            std::bind(std::forward<TFunction>(a_func),
                      std::forward<TArgs>(a_args)...)));
    }
    void call() const { func_(); }

private:
    using func_type = std::function<void()>;
    DelayedCaller(func_type&& a_ft) : func_(std::forward<func_type>(a_ft)) {}
    func_type func_;
};

int main()
{
    auto caller1(DelayedCaller::setup(&myFunc1, 123, 45.6));
    auto caller2(DelayedCaller::setup(&myFunc2, "A string"));

    caller1->call();
    caller2->call();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

123, 45.6
A string

返回一个智能指针,例如std::unique_ptr,而不是返回原始指针(或按值返回并避免动态分配.func_type如果参数是可移动的,则可移动,或者无论如何都可以非常便宜地复制.您可能需要定义移动构造函数和移动赋值运算符,它们是在某些条件下生成的).