Skip to content

Latest commit

 

History

History
73 lines (56 loc) · 2.23 KB

File metadata and controls

73 lines (56 loc) · 2.23 KB

条款32:适用初始化捕获将对象移入闭包

但是C++11却没有加入移动捕获特性,但是标准委员会在C++14提出了一种新的捕获机制,叫做 初始化捕获(init capture)

使用初始化捕获,你将得到机会指定:

  1. 由lambda生成的闭包类的成员变量的名字
  2. 一个表达式,用以初始化该成员变量

以下是如何使用初始化捕获将 std::unique_ptr 移动到闭包内的:

class Widget {
public:
    ...
    bool isValidated() const;
    bool isProcessed() const;
    bool isArchived() const;
private:
    ...
};
auto pw = std::make_unique<Widget>();
...
auto func = [pw = std::move(pw)]
            { return pw->isValidated()
                     && pw->isArchived(); };

位于 = 左侧的,是闭包类成员变量的名字,而位于右侧是是其初始化表达hi。上述捕获列表中将 pw 移入闭包内,实现了移动捕获。

可以看出,C++11“捕获”的概念在C++14中得到了泛化,因为在C++11中无法捕获一个表达式的结果。因此,初始化捕获还有另一个名字:广义lambda捕获

如果你一定要在C++11中用lambda表达式按移动捕获,只需要:

  1. 把需要捕获的对象移动到 std::bind 产生的函数对象中。
  2. 给到lambda表达式一个指向要捕获的对象的引用。

这是C++14的广义捕获:

std::vector<double> data;
...
auto func = [data = std::move(data)]
            {...};

在C++11中可以这样模拟:

std::vector<double> data;
...
auto func = 
    std::bind(
        [](const std::vector<double>& data)
        {...},
        std::move(data);
    );

const 修饰形参是为了保证lambda的常量语义,为了防止绑定对象里移动构造得到的 data 副本被意外修改,lambda的形参就声明为常量引用。

但是如果lambda表达式被 mutable 修饰,lambda的形参就不需要 const 修饰:

auto func = 
    std::bind(
        [](std::vector<double>& data) mutable
        {...},
        std::move(data);
    );

绑定对象是由源对象复制来的,绑定对象的生命期和闭包相同,所以针对绑定对象和闭包里的对象可以采用相同的手法加之处置。