【发布时间】:2021-02-10 17:20:07
【问题描述】:
在 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 的模板参数。我真的希望它成为调用方法的模板参数,而不是整个类。我这样做的原因是 arg_tuple 不知道存储的元组的类型,所以调用需要一个虚函数才能知道类型元组类型(typed_arg)。然而,虚拟方法不能有模板参数,所以这就是我卡住的地方。
如果有一种方法可以让 Callable 成为调用的模板方法,那么可以将其作为转发引用,这样我就不必按值获取它。否则,我想我可能需要对 lvalue、const lvalue 和 rvalue 引用进行多次重载,以防 Callable 是可变对象。
有没有更好的方法来做到这一点?
【问题讨论】:
-
我会使用 lambda,如果需要,可以将它传递给
std::function<void()>容器来保存它。