Lambda C+的未定义行为+;结束语:我
举个例子:Lambda C+的未定义行为+;结束语:我,lambda,c++11,closures,pass-by-reference,Lambda,C++11,Closures,Pass By Reference,举个例子: #include <iostream> #include <functional> // std::function #include <vector> // std::vector #include <algorithm> // std::for_each int main(){ auto adder = [](int x) { return [&](int y) {
#include <iostream>
#include <functional> // std::function
#include <vector> // std::vector
#include <algorithm> // std::for_each
int main(){
auto adder = [](int x) {
return [&](int y) {
return x+=y;
};
};
std::vector < std::function<int(int)> > vec;
vec.push_back(adder(1));
vec.push_back(adder(10));
std::for_each(vec.begin(), vec.end(), [](std::function<int(int)> f){std::cout << f(33) << " ";});
std::cout << std::endl;
}
#包括
#include//std::function
#include//std::vector
#包括。(编辑:这当然不能解释ICE;我读原始问题太匆忙了。)
该代码中的一个问题是,从加法器
函数返回的lambda包含对不再存在的x
变量的悬空引用。通过复制([=]
或[i]
)而不是引用([&]
)进行捕获,所有操作都应该有效。在您的示例中,似乎不能忽略尾随返回类型。以下是标准(5.1.2 Lambda表达式)的摘录:
如果lambda表达式没有
包括一个尾随返回类型,它是
好像后面的返回类型表示
以下类型:-如果复合语句的形式为{属性说明符seq return expression;}左值到右值转换(4.1)、数组到指针转换(4.2)和函数到指针转换(4.3)后返回的表达式的类型;-否则,无效
示例中的返回值不能用于上述转换。在VS 2010中编译以下带有明确添加的返回类型的代码:
auto adder = [] (int x) -> std::function<int (int)> {
return [=]( int y ) {
return x + y;
};
};
auto adder=[](int x)->std::function{
返回[=](整数y){
返回x+y;
};
};
你完全没有抓住要点。对std::function
的需求非常非常明显
所有lambda在编译时都有一个唯一的类型
您希望向量在运行时保存任何函数对象
因此,需要某种类型的擦除,这是std::function
所做的工作
您究竟如何才能创建一个在运行时根据编译时事实而变化的向量,比如其中包含的类型?这在逻辑上是不可能的——除非您使用诸如std::function
之类的抽象
当然,如果您只需要其中的一个lambda类型,那么您根本不需要std::function
。但这是相对罕见的
int main() {
auto adder = [](int x) {
return [=](int y) {
return x + y;
};
};
// alternatively- you MUST copy the argument as it will cease to exist
// but once it's in the lambda, you can use "mutable" to allow you to
// modify the copy that each lambda has.
/*
auto adder = [](int x) {
return [=](int y) mutable {
return x += y;
};
};
*/
std::vector<decltype(adder(0))> adders;
adders.emplace_back(adder(0));
adders.emplace_back(adder(1));
std::for_each(adders.begin(), adders.end(), [](decltype(*adders.begin())& ref) {
std::cout << ref(33);
});
std::cin.get();
}
intmain(){
自动加法器=[](整数x){
返回[=](整数y){
返回x+y;
};
};
//或者-必须复制参数,因为它将不再存在
//但是一旦它在lambda中,您就可以使用“可变”来允许您
//修改每个lambda拥有的副本。
/*
自动加法器=[](整数x){
返回[=](整数y)可变{
返回x+=y;
};
};
*/
矢量加法器;
加法器。向后放置(加法器(0));
加法器。向后放置(加法器(1));
std::for_each(adders.begin()、adders.end()、[](decltype(*adders.begin())&ref){
std::cout如果是“内部编译器错误”无论示例是否正确,GCC中肯定存在一个bug。感谢您注意到这一点。我通过引用捕获,它也应该可以工作。我的错误只是预期结果不应该是34和43,而应该是43和76,因为这是一个标准闭包,也就是说,它会记住,就像您在JavaScr中获得它一样如果用函数{}替换C++ LAMBDAS但是,这是一个次要的方面,对。不幸的是,C++中不可能通过在闭包中捕获自动变量来延长其生命周期;在一般情况下,它需要在语言层收集垃圾,同时在堆中存储自动变量。无论如何,具有相关可变状态的lambdas相当不正常;它们很难推理,而且与函数式编程范式截然相反。我想结论是,如果您需要在lambda的整个生命周期内值发生变化的变量,并且希望它位于创建它的范围之外,那么您需要编写一个完整的仿函数。@Ken Bloom:不,如果您需要的话只需将lambda声明为mutable
,然后就可以对已被值捕获的变量(因此不在创建它的范围内)进行变异,例如:return[=](int y)mutable{return x+=y;}
谢谢!这当然有帮助,gcc现在编译时没有错误,但我发布的第一个程序上仍然出现运行时错误:运行时错误是在抛出'std::bad_function_call'what():std::exception 144453761 144453794实例后被终止调用的。顺便问一句,编写lambda:auto m=[]()->returntype{},或者return_type m=[](){}完全没有自动,或者return_type m=[]()->return_type{}?我的意思是当我清楚地知道所有事情的时候。但是无论如何,非常感谢,你的评论揭示了一个新的事实,我只是没有足够的声誉(15)更新投票。如果我有任何发现,我将在几天后发布我的发现。我不明白:5.1.2:“对lambda表达式的评估会导致prvalue临时值。”但是如果您返回x+y
它也是一个prvalue临时值。因此不需要进行转换。解释:如果您在lambda表达式中返回lambda表达式,则结果是prvalue临时值。如果您返回x+y
则结果也是一个prvalue临时值。因此,没有理由认为第一个是非法的,第二个是无效的法律。你提供了一个非常宏伟的规模的精彩答案。我现在想读更多关于C++的文章,非常感谢你的时间。我们在基本上同时写了答案,所以当我找到一个工作技巧我对你的输入不太了解。你是对的,特别是在想法层面上,但是你的程序没有在GCC 4上编译。.6.0,同样的东西:g++:内部编译器错误:分段错误(程序cc1plus)。但它可以进行一些修改。我喜欢你解释std::function的方式。我将再发布一个答案,只是为了澄清一些事情。@RustyJames:我很确定它应该按照最新的C++0x工作草案进行编译,但当然,实现还没有完成