【问题标题】:What is the best way to save function arguments and call the function later?保存函数参数并稍后调用函数的最佳方法是什么?
【发布时间】: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&lt;void()&gt; 容器来保存它。

标签: c++ templates stdtuple


【解决方案1】:

有几种方法可以做到这一点。

使用未来:

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();

【讨论】:

  • 还有std::packaged_task,它是一个轻量级版本std::async,它始终是std::launch::deferred
猜你喜欢
  • 1970-01-01
  • 2016-09-19
  • 2021-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多