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工作草案进行编译,但当然,实现还没有完成