为什么非可变lambda中的字段在捕获常量值或常量引用时使用“const”?

正如问题lambda capture by value mutable 中所见,它不适用于 const &? , 当const T&使用其名称或[=]可变 lambda捕获类型的值时,隐藏类中的字段获取类型const T。可以争论的是,这对于可变 lambda 来说是正确的做法。

但是为什么对非可变 lambda 也这样做呢?在非可变 lambda 表达式中,operator()(...)is 被声明const,因此无论如何它都不能修改捕获的值。

当我们移动 lambda 时,例如将它包装在std::function.

请参阅以下两个示例:

#include <cstdio>
#include <functional>

std::function<void()> f1, f2;

struct Test {
    Test() {puts("Construct");}
    Test(const Test& o) {puts("Copy");}
    Test(Test&& o) {puts("Move");}
    ~Test() {puts("Destruct");}
};

void set_f1(const Test& v) {
    f1 = [v] () {}; // field type in lambda object will be "const Test"
}

void set_f2(const Test& v) {
    f2 = [v = v] () {}; // field type in lambda object will be "Test"
}

int main() {
    Test t;
    puts("set_f1:");
    set_f1(t);
    puts("set_f2:");
    set_f2(t);
    puts("done");
}

我们得到以下编译器生成的 lambda 类:

class set_f1_lambda {
    const Test v;
public:
    void operator()() const {}
};

class set_f2_lambda {
    Test v;
public:
    void operator()() const {}
};

该程序打印以下内容(使用 gcc 或 clang):

Construct
set_f1:
Copy
Copy
Copy
Destruct
Destruct
set_f2:
Copy
Move
Move
Destruct
Destruct
done
Destruct
Destruct
Destruct

v在第一个示例中,该值被复制不少于 3 次set_f1

在第二个示例中set_f2,唯一的副本是在捕获值时(如预期的那样)。使用两次移动这一事实是 libstdc++ 中的一个实现细节。当按值将函子传递给内部函数时,第一步发生在operator=instd::function内部(为什么此函数签名不使用按引用传递?)。第二个移动发生在移动构造最终堆分配的函子时。

但是,如果字段是 const(因为这样的构造函数在窃取其内容后无法“清除”const 变量)。这就是为什么必须将复制构造函数用于此类字段的原因。

所以对我来说,像const在非可变 lambdas 中一样捕获值似乎只有负面影响。我是否遗漏了一些重要的东西,或者它只是通过这种方式标准化以某种方式使标准更简单?

以上是为什么非可变lambda中的字段在捕获常量值或常量引用时使用“const”?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>