保存函数参数并稍后调用函数的最佳方法是什么?
What is the best way to save function arguments and call the function later?
在 C++14 中,我希望能够保存函数参数并在以后调用该函数。我的目标是能够做类似的事情:
auto delayed_function{ some_callable };
delayed_function( 1, 2, 3 ); // arguments are stored, but some_callable is not called yet
delayed_function.call(); // some_callable called with (1,2,3)
主要问题是我需要获取参数并存储它们。似乎将它们存储在 std::tuple 中效果最好。问题是元组的类型到底应该是什么。我的想法是,我需要在提供参数时推断出元组的类型(而不是试图从参数推断出可调用对象的类型),因为在提供参数时,它们可能是引用、右值等。 ,我只会从参数类型中知道这一点。然而,这意味着即使我知道可调用对象的类型,我也不知道元组的类型,除非在提供参数的模板方法中(我上面的示例中的 operator())。所以听起来我需要某种类型的擦除。我目前对参数存储的实现是:
template <typename Callable>
class arg_tuple
{
public:
template <typename ... Args>
arg_tuple( Args&&... args )
{
using TupleType = decltype( std::make_tuple(std::forward<Args>(args)...) );
args_ =
std::make_unique< typed_arg<TupleType> >(
std::make_tuple(std::forward<Args>(args)...)
);
}
void
invoke( Callable f )
{
args_->invoke( f );
}
private:
template <typename T = void>
struct untyped_arg {
virtual ~untyped_arg() = default;
virtual void invoke( Callable f ) = 0;
};
template <typename T>
struct typed_arg
: public untyped_arg<> {
template <typename Arg>
typed_arg( Arg&& arg )
: value(std::forward<Arg>(arg) ) {}
virtual void
invoke( Callable f )
{
// By moving value, I can only call invoke once, but it potentially saves
// copying, and I can use move-only types in the arg list.
my_apply( f, std::move(value) );
}
T value;
};
std::unique_ptr<untyped_arg<>> args_;
};
其中“my_apply”本质上是 std::apply,但由于我使用的是 C++14,因此我不得不手动实现它。好消息是这基本上有效:
auto f = [](int i) { printf("i+3=%d\n", i+3); };
using Callable = decltype(f);
arg_tuple<Callable> t(20);
t.invoke(f);
然而,让我困扰的是 Callable 是 arg_tuple 的模板参数。我真的希望它成为调用方法的模板参数,而不是整个 class。我这样做的原因是 arg_tuple 不知道存储元组的类型,所以 invoke 需要一个虚函数才能找到元组类型已知的地方(typed_arg).然而,虚拟方法不能有模板参数,所以这就是我卡住的地方。
如果有一种方法可以使 Callable 成为调用的模板方法,那么就可以使它成为转发引用,这样我就不必按值接受它了。否则,我想我可能需要对左值、const 左值和右值引用进行多次调用重载,以防 Callable 是可变对象。
有更好的方法吗?
有几种方法可以做到这一点。
使用未来:
auto value = std::async(std::launch::deferred, delayed_function, 1, 2, 3);
...
value.get();
或者只使用 lambda:
auto f = [arg]() { return delayed_function(arg, 2, 3); }
...
f();
在 C++14 中,我希望能够保存函数参数并在以后调用该函数。我的目标是能够做类似的事情:
auto delayed_function{ some_callable };
delayed_function( 1, 2, 3 ); // arguments are stored, but some_callable is not called yet
delayed_function.call(); // some_callable called with (1,2,3)
主要问题是我需要获取参数并存储它们。似乎将它们存储在 std::tuple 中效果最好。问题是元组的类型到底应该是什么。我的想法是,我需要在提供参数时推断出元组的类型(而不是试图从参数推断出可调用对象的类型),因为在提供参数时,它们可能是引用、右值等。 ,我只会从参数类型中知道这一点。然而,这意味着即使我知道可调用对象的类型,我也不知道元组的类型,除非在提供参数的模板方法中(我上面的示例中的 operator())。所以听起来我需要某种类型的擦除。我目前对参数存储的实现是:
template <typename Callable>
class arg_tuple
{
public:
template <typename ... Args>
arg_tuple( Args&&... args )
{
using TupleType = decltype( std::make_tuple(std::forward<Args>(args)...) );
args_ =
std::make_unique< typed_arg<TupleType> >(
std::make_tuple(std::forward<Args>(args)...)
);
}
void
invoke( Callable f )
{
args_->invoke( f );
}
private:
template <typename T = void>
struct untyped_arg {
virtual ~untyped_arg() = default;
virtual void invoke( Callable f ) = 0;
};
template <typename T>
struct typed_arg
: public untyped_arg<> {
template <typename Arg>
typed_arg( Arg&& arg )
: value(std::forward<Arg>(arg) ) {}
virtual void
invoke( Callable f )
{
// By moving value, I can only call invoke once, but it potentially saves
// copying, and I can use move-only types in the arg list.
my_apply( f, std::move(value) );
}
T value;
};
std::unique_ptr<untyped_arg<>> args_;
};
其中“my_apply”本质上是 std::apply,但由于我使用的是 C++14,因此我不得不手动实现它。好消息是这基本上有效:
auto f = [](int i) { printf("i+3=%d\n", i+3); };
using Callable = decltype(f);
arg_tuple<Callable> t(20);
t.invoke(f);
然而,让我困扰的是 Callable 是 arg_tuple 的模板参数。我真的希望它成为调用方法的模板参数,而不是整个 class。我这样做的原因是 arg_tuple 不知道存储元组的类型,所以 invoke 需要一个虚函数才能找到元组类型已知的地方(typed_arg).然而,虚拟方法不能有模板参数,所以这就是我卡住的地方。
如果有一种方法可以使 Callable 成为调用的模板方法,那么就可以使它成为转发引用,这样我就不必按值接受它了。否则,我想我可能需要对左值、const 左值和右值引用进行多次调用重载,以防 Callable 是可变对象。
有更好的方法吗?
有几种方法可以做到这一点。
使用未来:
auto value = std::async(std::launch::deferred, delayed_function, 1, 2, 3);
...
value.get();
或者只使用 lambda:
auto f = [arg]() { return delayed_function(arg, 2, 3); }
...
f();