lambda捕获何时被初始化?

时间:2016-08-04 13:14:38

标签: c++ lambda

在以下函数中,我可以依赖捕获的变量'order'来更新,即

  1. 该功能是否始终按预期工作?
  2. 按值或参考捕获之间是否存在差异。
  3. 功能是否可重入?
  4. struct Entry
    {
        std::string name;
        double earnings;
    };
    
    enum Column { Name, Earnings };
    enum SortOrder { Ascending, Descending };
    
    void sortByColumn(std::vector<Entry>& entries, Column column, SortOrder order)
    {
        std::function<bool(const Entry&, const Entry&)> comparators[] =
        {
            [&](const Entry& a, const Entry& b) { return order==Ascending ?
                a.name < b.name : a.name > b.name;  },
            [=](const Entry& a, const Entry& b) { return order==Ascending ?
                a.earnings < b.earnings : a.earnings > b.earnings;  }
        };
        std::sort(entries.begin(), entries.end(), comparators[column]);
    }
    

    您可以在此处找到完整示例:http://coliru.stacked-crooked.com/a/240b74d1706a1b6f

2 个答案:

答案 0 :(得分:2)

你必须认识到的是lambda是一个闭包类型的对象:

  

lambda表达式是一个prvalue表达式,是一个未命名的唯一非联合非聚合类类型的临时对象,称为闭包类型,在最小块范围内声明(出于Argument-Dependent Lookup的目的),类范围或包含lambda表达式 [source]

的命名空间范围

您可以将lambda的捕获列表视为构造函数参数。在这种情况下,您通过值/引用将order分别传递到1 st / 2 nd comparators由于ordercomparators的生命周期内没有变化,因此通过引用或值传递将在您的示例中得到相同的结果。

但是如果调用此函数并将order设置为Ascending,并将其添加到sortByColumn的底部:

order = Descending;
std::sort(entries.begin(), entries.end(), comparators[0]);

您可以按{strong>降序顺序按entries排序name。意味着对order的更改影响了lambda。

如果您已完成此操作,sortByColumn再次成为order Ascending

order = Descending;
std::sort(entries.begin(), entries.end(), comparators[1]);

您可以按{strong>升序顺序按entries排序earnings。意味着对order的更改不会影响lambda。

在决定是否通过引用捕获时,应该应用相同的注意事项,用于决定是否将引用或副本用作对象成员:

  1. 如果对象无法复制构建,则必须使用引用,如果复制构造昂贵,您可以选择以使用引用
  2. 如果lambda的生命周期超过了它捕获的生命周期,你必须复制一份,如果你提供的话,你可以选择使用make copy。 lambda将在代码外部使用

答案 1 :(得分:2)

  1. 代码按预期工作。
  2. 当然有区别。虽然在这个例子中它没有改变最终结果,但我更喜欢按值捕获。原因是它只是你正在捕获的基类型,并且lambda中没有写操作。此外,总是明确捕捉它的好风格:
  3.     std::function<bool(const Entry&, const Entry&)> comparators[] =
        {
            [order](const Entry& a, const Entry& b) { return order==Ascending ? a.name < b.name : a.name > b.name;  },
            [order](const Entry& a, const Entry& b) { return order==Ascending ? a.earnings < b.earnings : a.earnings > b.earnings;  }
        };
    
    1. sortByColumn是可以重入的。除了更改entries之外,它没有任何状态,也没有副作用。
    2. 如果你关心性能,最好检查lambda之外的order排序并将lambda直接传递给std::sort,而不是将其放入std::function。首先你需要四种不同的lambdas。