当使用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;
你在混合两件事--通过引用传递和转换。
这大致是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
对象,该对象创建自己的count
lambda对象的本地副本。 当然,对于invoke1
调用也发生了同样的情况,但这没有什么区别,因为无论哪种方式都可以进行复制。
请注意,invoke2(const function&;)
中的常量非常重要,没有它,调用将导致编译错误。 这是因为常量函数&;
允许参数绑定到L值和R值(~temporaries)。