我编写了一个模板代码,它以仿函数作为参数,经过一些处理后,执行它。虽然其他人可能会将该函数传递给lambda,函数指针甚至是std::function
,但它主要用于lambda(不是我禁止其他格式)。我想问一下,我应该怎样拿这个lambda - 按价值?引用?或其他什么。
示例代码 -
#include <iostream>
#include <functional>
using namespace std;
template<typename Functor>
void f(Functor functor)
{
functor();
}
void g()
{
cout << "Calling from Function\n";
}
int main()
{
int n = 5;
f([](){cout << "Calling from Temp Lambda\n";});
f([&](){cout << "Calling from Capturing Temp Lambda\n"; ++n;});
auto l = [](){cout << "Calling from stored Lambda\n";};
f(l);
std::function<void()> funcSTD = []() { cout << "Calling from std::Function\n"; };
f(funcSTD);
f(g);
}
在上面的代码中,我可以选择将其中任何一个 -
template<typename Functor>
void f(Functor functor)
template<typename Functor>
void f(Functor &functor)
template<typename Functor>
void f(Functor &&functor)
更好的方法是什么?为什么?这些都有任何限制吗?
答案 0 :(得分:7)
作为一个可能的缺点,请注意,如果lambda不可复制,则通过副本传递不起作用。如果你可以逃脱它,通过副本就可以了 举个例子:
#include<memory>
#include<utility>
template<typename F>
void g(F &&f) {
std::forward<F>(f)();
}
template<typename F>
void h(F f) {
f();
}
int main() {
auto lambda = [foo=std::make_unique<int>()](){};
g(lambda);
//h(lambda);
}
在上面的代码段中,由于lambda
,foo
无法复制。由于std::unique_ptr
的复制构造函数被删除,因此删除了其复制构造函数
另一方面,F &&f
接受左值和左值引用作为转发引用,以及const引用。
换句话说,如果你想多次重复使用相同的lambda作为参数,你就不能通过复制得到你的对象而你必须移动它,因为它不可复制(嗯,实际上你可以,这是一个将它包装在lambda中的问题,通过引用捕获外部的一个。)
答案 1 :(得分:4)
由于lambda表达式可以有自己的字段(如类),复制/使用引用可能会导致不同的结果。这是一个简单的例子:
template<class func_t>
size_t call_copy(func_t func) {
return func(1);
}
template<class func_t>
size_t call_ref(func_t& func) {
return func(1);
}
int main() {
auto lambda = [a = size_t{0u}] (int val) mutable {
return (a += val);
};
lambda(5);
// call_ref(lambda); – uncomment to change result from 5 to 6
call_copy(lambda);
std::cout << lambda(0) << std::endl;
return 0;
}
顺便说一下,如果你想通过表现来判断它,实际上没有区别,lambda非常小,很容易复制。
另外 - 如果你想传递lambda作为参数(而不是包含它的变量),你应该使用转发引用,这样它才能工作。