将所有参数移动到lambda

时间:2016-01-26 09:03:21

标签: c++ lambda variadic-templates perfect-forwarding

我想创建可接受任意数量参数的lambda,如:

template <typename... Args>
void f(Args... args) {
    auto l = [args...]() {
        g(args...);
    }
    // use l
}

问题在于它不适用于仅移动类型。如果它只有1 arg我会像

那样做
void f(Arg arg) {
    auto l = [arg = std::move(arg)]() {
        g(move(arg));
    }
}

如何将所有args移动到lambda?

1 个答案:

答案 0 :(得分:8)

template <class... Args>
void f(Args... args) {
  auto l = [tup=std::make_tuple(std::move(args)...)] {
    std::apply([](auto&&...args){
      g(decltype(args)(args)...);
    }, tup );
  };
}

有点icky。

将它们打包成一个元组,然后用std::apply解包元组。如果你缺少std::apply给自己写一个等价的。

如果要使用rvalues调用g,请将外部lambda设为mutable,将move元组设置为内部lambda。

如果你想要访问外部的args等,内部lambda可以默认捕获&

我们甚至可以抽象一下这个模式:

template<class F, class...Args>
auto forward_capture( F&& f, Args&&...args ) {
  return [
    f=std::forward<F>(f),
    tup=std::make_tuple(std::forward<Args>(args)...)
  ]{
    return std::apply( f, tup );
  };
}

使用:

template <typename... Args>
void f(Args... args) {
  auto l = forward_capture(
    [](auto&&...args) {
      g(args...);
    },
    std::move(args)...
  );
  // use l
}

如果您想先获取捕获列表,我们可以这样做:

template<class...Args>
auto forward_capture( Args&&...args ) {
  return [
    tup=std::make_tuple(std::forward<Args>(args)...)
  ](auto&& f)mutable{
    return [
      f=decltype(f)(f),
      tup=std::move(tup)
    ]{
      return std::apply( f, tup );
    };
  };
}

使用:

template <typename... Args>
void f(Args... args) {
  auto l = forward_capture(std::move(args)...)(
    [](auto&&...args) {
      g(args...);
    }
  );
  // use l
}

具有&#34;优势&#34;我们有3个嵌套的lambdas。

或者更有趣:

template<class...Args>
struct arrow_star {
    std::tuple<Args...> args;
    template<class F>
    auto operator->*(F&& f)&& {
      return [f=std::forward<F>(f),args=std::move(args)]()mutable{
        return std::experimental::apply( std::move(f), std::move(args) );
      };
    }
};
template<class...Args>
arrow_star<std::decay_t<Args>...> forward_capture( Args&&...args ) {
  return {std::make_tuple(std::forward<Args>(args)...)};
}
template<class...Args>
auto f(Args... args)
{
  return
    forward_capture( std::move(args)... )
    ->*
    [](auto&&...args){
      g(decltype(args)(args)...);
    };
}

live example