C++ 为什么C++;11';s lambda require";可变的;默认情况下,按值捕获的关键字?
简短示例:C++ 为什么C++;11';s lambda require";可变的;默认情况下,按值捕获的关键字?,c++,lambda,c++11,C++,Lambda,C++11,简短示例: #include <iostream> int main() { int n; [&](){n = 10;}(); // OK [=]() mutable {n = 20;}(); // OK // [=](){n = 10;}(); // Error: a by-value capture cannot be modified in a non-mutable lambda
#include <iostream>
int main()
{
int n;
[&](){n = 10;}(); // OK
[=]() mutable {n = 20;}(); // OK
// [=](){n = 10;}(); // Error: a by-value capture cannot be modified in a non-mutable lambda
std::cout << n << "\n"; // "10"
}
#包括
int main()
{
int n;
[&](){n=10;}();//确定
[=]()可变的{n=20;}();//确定
//[=](){n=10;}();//错误:无法在不可变的lambda中修改按值捕获
标准::cout见第5.1.2款[解释初始lambda],第5款:
lambda表达式的闭包类型有一个公共内联函数调用运算符(13.5.4),其参数
和返回类型由lambda表达式的参数声明子句和trailingreturn描述-
分别键入。当且仅当lambdaexpression
参数声明子句后面没有可变项。
编辑litb的评论:
也许他们想到了按值捕获,这样变量的外部更改就不会反映在lambda中?引用是双向的,所以这就是我的解释。但我不知道这是否有用
编辑kizzx2的评论:
lambda最常被用作算法的函子。默认的const
ness允许它在一个恒定的环境中使用,就像普通的const
-在那里可以使用限定的函数,但非限定的函数不能。也许他们只是想让这些情况更直观,谁知道呢现在他们在想什么。:)
我的印象是,按值捕获的整个要点是允许用户更改临时值——否则,使用引用捕获几乎总是更好,不是吗
问题是,它“几乎”吗?一个常见的用例似乎是返回或传递lambdas:
void registerCallback(std::function<void()> f) { /* ... */ }
void doSomething() {
std::string name = receiveName();
registerCallback([name]{ /* do something with name */ });
}
void registerCallback(std::function f){/*…*/}
无效剂量测定法(){
std::string name=receiveName();
registerCallback([name]{/*使用name*/}执行某些操作);
}
<>我认为<代码>易变的<代码>不是一个“几乎”的例子。我认为“价值捕获”就像“允许我在被捕获的实体死后使用它的价值”,而不是“允许我改变它的副本”。。但这可能是有争议的。您需要思考Lambda函数的闭包类型是什么。每次声明Lambda表达式时,编译器都会创建一个闭包类型,它只不过是一个带有属性的未命名类声明(声明Lambda表达式的环境)函数调用::operator()
已实现。当您使用按值复制捕获变量时,编译器将在闭包类型中创建一个新的const
属性,因此您不能在Lambda表达式中更改它,因为它是一个“只读”属性,这就是他们将其称为“结束",因为在某种程度上,您是通过将变量从上限范围复制到Lambda范围来关闭Lambda表达式。当您使用关键字mutable
时,捕获的实体将成为闭包类型的非常量属性。这就是导致在通过值捕获的可变变量中所做的更改不可用的原因可以传播到更高的作用域,但保持在有状态Lambda内。
始终尝试想象Lambda表达式的结果闭包类型,这对我有很大帮助,我希望它也能帮助你。它需要可变,因为默认情况下,函数对象每次调用时都应该产生相同的结果。这就是面向对象的函数和使用glo的函数之间的区别bal变量,有效
我的印象是
按价值捕获的整个要点是
允许用户更改临时设置
--否则,使用引用捕获几乎总是更好,不是吗
我
n
不是临时的。n是使用lambda表达式创建的lambda函数对象的成员。默认期望是调用lambda不会修改其状态,因此它是常量,以防止您意外修改n
您的代码几乎等同于此:
#include <iostream>
class unnamed1
{
int& n;
public:
unnamed1(int& N) : n(N) {}
/* OK. Your this is const but you don't modify the "n" reference,
but the value pointed by it. You wouldn't be able to modify a reference
anyway even if your operator() was mutable. When you assign a reference
it will always point to the same var.
*/
void operator()() const {n = 10;}
};
class unnamed2
{
int n;
public:
unnamed2(int N) : n(N) {}
/* OK. Your this pointer is not const (since your operator() is "mutable" instead of const).
So you can modify the "n" member. */
void operator()() {n = 20;}
};
class unnamed3
{
int n;
public:
unnamed3(int N) : n(N) {}
/* BAD. Your this is const so you can't modify the "n" member. */
void operator()() const {n = 10;}
};
int main()
{
int n;
unnamed1 u1(n); u1(); // OK
unnamed2 u2(n); u2(); // OK
//unnamed3 u3(n); u3(); // Error
std::cout << n << "\n"; // "10"
}
#包括
未命名类1
{
国际及北;
公众:
未命名1(int&N):N(N){}
/*好的,这是常量,但不修改“n”引用,
但是它所指向的值。您将无法修改引用
无论如何,即使运算符()是可变的。分配引用时
它将始终指向同一个var。
*/
void运算符()()常量{n=10;}
};
未命名类别2
{
int n;
公众:
未命名2(int N):N(N){}
/*好的。这个指针不是常量(因为运算符()是“可变的”,而不是常量)。
因此,您可以修改“n”成员*/
void运算符(){n=20;}
};
未命名类3
{
int n;
公众:
未命名3(int N):N(N){}
/*不好。您的帐户为常量,因此无法修改“n”成员*/
void运算符()()常量{n=10;}
};
int main()
{
int n;
未命名1 u1(n);u1();//确定
未命名的2 u2(n);u2();//确定
//未命名3 u3(n);u3();//错误
在C++的标准化委员会的著名成员中,萨特提出了一个不同的答案:
考虑这个稻草人的例子,程序员通过
值,并尝试修改
捕获的值(是lambda对象的成员变量):
添加此功能似乎是出于用户的担忧
可能没有意识到他得到了一份拷贝,尤其是自从lambdas
可复制他可能正在更改lambda的另一份副本
他的论文是关于为什么这应该在C++14中更改的。它很短,写得很好,如果你想知道“我身上有什么东西”的话,值得一读
int val = 0;
auto x = [=](item e) // look ma, [=] means explicit copy
{ use(e,++val); }; // error: count is const, need ‘mutable’
auto y = [val](item e) // darnit, I really can’t get more explicit
{ use(e,++val); }; // same error: count is const, need ‘mutable’
int main()
{
using namespace std;
int x = 5;
int y;
auto lamb = [x]() {return x + 5; };
y= lamb();
cout << y<<","<< x << endl; //outputs 10,5
x = 20;
y = lamb();
cout << y << "," << x << endl; //output 10,20
}
int main()
{
using namespace std;
int x = 5;
int y;
auto lamb = [x]() mutable {return x++ + 5; };
y= lamb();
cout << y<<","<< x << endl; //outputs 10,5
x = 20;
y = lamb();
cout << y << "," << x << endl; //outputs 11,20
}