提问者:小点点

Lambda(通过引用与值向函数传递Lambda)


当使用lambda创建std::函数时,std::函数在内部创建lambda对象的副本。 因此,我们对fn()的调用实际上是在我们的lambda的副本上执行的,而不是在实际的lambda上执行的。

根据上面的陈述,通过“引用使用&;”传递lambda有什么意义 或者在下面的代码中传递'value',而std::函数总是创建lambda对象的副本?

换句话说,在下面的代码中,当'invoke'函数的参数通过引用或值传递时,lambda的哪个部分将被修改或不被影响?

#include <iostream>
#include <functional>
 
void invoke(const std::function<void(void)>& fn) // # PASS LAMBDA BY REFERENCE*********************
 
{
    fn();
}
 
int main()
{
    int i{ 0 };
 
    // Increments and prints its local copy of @i.
    auto count{ [i]() mutable {
      std::cout << ++i << '\n';
    } };
 
    invoke(count);
    invoke(count);
    invoke(count);
 
    return 0;
}

#include <iostream>
#include <functional>
 
void invoke(const std::function<void(void)> fn) // # PASS LAMBDA BY VALUE*********************
{
    fn();
}
 
int main()
{
    int i{ 0 };
 
    // Increments and prints its local copy of @i.
    auto count{ [i]() mutable {
      std::cout << ++i << '\n';
    } };
 
    invoke(count);
    invoke(count);
    invoke(count);
 
    return 0;

共1个答案

匿名用户

你在混合两件事--通过引用传递和转换。

这大致是lambdas的实现方式:

struct Lambda{
    //Capture by value
    Lambda(int i):_i(i){}

    void operator()() const{
        std::cout << ++_i << '\n';
    }
    mutable int _i;
};
//BTW const is somewhat redundant
void invoke1(const Lambda fn) // # PASS LAMBDA BY VALUE
{
    fn();
}
//Const is important, but not yet.
void invoke2(const Lambda& fn) // # PASS LAMBDA BY REFERENCE
{
    fn();
}
 
int main()
{
    int i{ 0 };
 
    // Increments and prints its local copy of @i.
    Lambda count{i};
 
    invoke1(count);//1
    invoke1(count);//1
    invoke1(count);//1

    invoke2(count);//1
    invoke2(count);//2
    invoke2(count);//3
 
    return 0;
}

代码生成您可能想要的输出。 注意,mutable用法是完全不正确的,但是我这样做是为了代码编译。 有关std::function如何执行此操作,请参见链接。

正如@Jarod42所写的,lambda不是一个std::function,但它可以通过std::function的构造函数隐式地转换为一个。 这根本不是std::function的实现方式,为了允许捕获任何可调用函数,还涉及到更多的魔术。 但它说明了这一点。

#include <iostream>
#include <functional>
 
struct Lambda{
    //Capture by value
    Lambda(int i):_i(i){}

    void operator()() const{
        std::cout << ++_i << '\n';
    }
    mutable int _i;
};

struct Function{
    //Makes a copy.
    Function(Lambda lambda):_lambda(std::move(lambda)){}

    void operator()() const{
        _lambda();
    }

    Lambda _lambda;
};


void invoke1(const Function fn) // # PASS FUNCTION BY VALUE
{
    fn();
}
//Const is very important.
void invoke2(const Function& fn) // # PASS FUNCTION BY REFERENCE
{
    fn();
}
 
int main()
{
    int i{ 0 };
 
    // Increments and prints its local copy of @i.
    Lambda count{i};
 
    invoke1(count);//1
    invoke1(count);//1
    invoke1(count);//1

    invoke2(count);//1
    invoke2(count);//1
    invoke2(count);//1
    
 
    return 0;
}

所有invoke2调用仍然打印1,因为每次调用时都会创建一个新的function对象,该对象创建自己的countlambda对象的本地副本。 当然,对于invoke1调用也发生了同样的情况,但这没有什么区别,因为无论哪种方式都可以进行复制。

请注意,invoke2(const function&;)中的常量非常重要,没有它,调用将导致编译错误。 这是因为常量函数&;允许参数绑定到L值和R值(~temporaries)。