对于一个库,我想要一个接受另一个函数及其参数的函数,然后将它们存储起来以便稍后调用。参数必须允许任何类型的混合,但函数只需要返回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"
一种方法是让DelayedCaller :: setup()接受一个std :: function,让我的库用户在调用setup()之前使用std :: bind()。但是,有没有办法实现setup(),以便用户不需要自己进行绑定?
编辑:DelayedCaller是一个现有的类。 setup()是一个我想添加的新静态方法。
答案 0 :(得分: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"
这也为您图书馆的用户提供了更大的灵活性。它们不仅限于单个函数调用,并且函数可以访问它们在其中创建的原始环境:
int x;
DelayedCaller caller3 = [&x]() {
if (x == 0)
DoSomething();
else
DoSomethingElse();
};
答案 1 :(得分:7)
可能是使用可变参数模板并从setup()
函数中调用std::bind()
:
#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;
}
输出:
123, 45.6 A string
返回一个智能指针,例如std::unique_ptr
,而不是返回一个原始指针(或按值返回并避免动态分配。如果参数是可移动的,func_type
是可移动的,或者它可能是反正相当便宜。你可能需要定义移动构造函数和移动赋值运算符,它们是在某些条件下生成的。)
答案 2 :(得分:0)
如果您希望/能够使用C ++ 11 future 库,您可以使用std::async
#include <future>
auto caller = std::async(myFunc1, 123, 45.6); // Creates a future object.
caller.get(); // Waits for the function to get executed and returns result.
强制使用延迟评估:
auto caller = std::async(std::launch::deferred, myFunc1, 123, 45.6);
此外,这还有一个优点,即函数调用可以在使用多核硬件的不同线程上执行。然而,这可能并不适用于所有情况。
答案 3 :(得分:0)
如果你唯一关心的是在保持界面的同时隐藏来自callsite的参数绑定,请使用variadic模板
class DelayedCaller
{
public:
template<typename... Args>
static DelayedCaller* setup(void (functionPtr*)(Args...), Args&&... args)
{
return new DelayedCaller(std::bind(functionPtr, std::forward<Args>(args)...));
}
DelayedCaller(const std::function<void()>& f) : f(f) {}
private:
std::function<void()> f;
};
公共构造函数仍然为您的用户提供了使用lambda初始化它的可能性。