Item 32: Use init capture to move objects into closures.

Effective Modern C++ Item 32 的学习和解读。

如果你想移动一个对象都 lambda 闭包,值捕获和引用捕获都不能实现该目的。C++ 14 提供了初始化捕获(init capture)模式支持移动捕获。C++11 并不支持,但是可以使用 std::bind 间接模拟。

C++14 使用初始化捕获模式实现移动捕获

C++14 提供了支持移动捕获的机制,但并没有类似值捕获 [=] 或者引用捕获 [&] 的模式直接添加一个移动捕获 [&&] 模式。而是采取了一种更加灵活的机制 ----- 初始化捕获模式。移动捕获是采用初始化捕获的机制实现,除了默认捕获模式,初始化捕获模式可以做原来 C++11 支持的所有捕获模式能做的事,甚至还更多,比如 item31 中介绍的类成员变量的捕获。初始化捕获模式语法如下:

  • 指定闭包类的成员名称。
  • 指定一个表达式来初始化这个成员。

看下面的例子:移动一个 std::unique_ptr 对象到 lambda 闭包。

class Widget { // some useful type
public:bool isValidated() const;
  bool isProcessed() const;
  bool isArchived() const;
private:};

auto pw = std::make_unique<Widget>(); // create Widget;
                                      // see Item 21 for info on
                                      // std::make_unique// configure *pw
auto func = [pw = std::move(pw)]                // init data mbr
            { return pw->isValidated()          // in closure w/
                     && pw->isArchived(); };    // std::move(pw)

在捕获列表中,“=” 左边的 pw 是指定的 lambda 闭包的成员名称。“=” 右边的 std::move(pw) 是指定的用于初始化闭包成员 pw 的表达式。“=” 两边的作用域也不一样,左边的作用域在 lambda 闭包中,右边的作用域是 lambda 表达式被定义的作用域。

C++11 使用 std::bind 间接实现移动捕获

C++11 使用 std::bind 间接实现移动捕获:

  • 将被捕获对象移动至 std::bind 产生的函数对象中。
  • 给 lambda 表达式一个被捕获对象的引用。

看下面的例子:

std::vector<double> data;auto func =
  std::bind(                            // C++11 emulation
    [](const std::vector<double>& data) // of init capture
    { /* uses of data */ },
    std::move(data)
);

和 lambda 表达式类似,std::bind 产生一个函数对象,称为绑定函数对象。std::bind 的第一个参数是可调用对象,紧接着的参数是传递给这个对象的值。

对于 std::bind 传递的参数,如果是左值,则拷贝到绑定函数对象中;如果是右值,则移动到绑定函数对象中。但是对于绑定函数对象而言,它的参数是一个左值引用。在这个例子中,std::bind 传递的是一个右值 std::move(data)func 内部调用移动构造来初始化 data

默认的,lambda 闭包内的 operator() 成员方法是一个 const 的,不能对参数进行修改,所以这里显示申明成 const。如果你希望可以对参数进行修改,则可以使用 mutable关键字进行修饰。

auto func =
  std::bind( // C++11 emulation
   [](std::vector<double>& data) mutable // of init capture
   { /* uses of data */ }, // for mutable lambda
   std::move(data)
);

再给一个前面 C++14 std::unique_ptr 移动到 lambda 闭包的例子。

C++14 的实现如下:

auto func = [pw = std::make_unique<Widget>()] // as before,
            { return pw->isValidated()        // create pw
                     && pw->isArchived(); };  // in closure

C++11 间接实现如下:

auto func = std::bind(
              [](const std::unique_ptr<Widget>& pw)
              { return pw->isValidated()
                       && pw->isArchived(); },
              std::make_unique<Widget>()
            );

最后,总结下本文:

  • C++14 使用初始化捕获模式实现移动捕获。
  • C++11 使用 std::bind 间接实现移动捕获。
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值