I've written a template code that takes a functor as an argument and after some processing, executes it. Although someone else might pass that function a lambda, a function pointer or even an std::function
but it is meant primarily for lambda(not that I ban other formats). I want to ask how should I take that lambda - by value? by reference? or something else.
我已经编写了一个模板代码,它以一个函数作为参数,经过一些处理后,执行它。尽管其他人可能会传递那个函数一个lambda、一个函数指针,甚至一个std::function,但是它主要是为lambda而设计的(不是我禁止其他格式)。我想问的是,我应该怎么取这个值?通过引用?或者其他东西。
Example code -
示例代码:
#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);
}
In above code, I've a choice of making it either of these -
在上面的代码中,我有两个选择
template<typename Functor>
void f(Functor functor)
template<typename Functor>
void f(Functor &functor)
template<typename Functor>
void f(Functor &&functor)
What would be the better way and why? Are there any limitations to any of these?
什么是更好的方式,为什么?这些有什么限制吗?
2 个解决方案
#1
4
As a possible drawback, note that passing by copy could not work if the lambda isn't copyable. If you can get away with it, passing by copy is just fine.
As an example:
作为一个可能的缺点,请注意,如果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);
}
In the snippet above, lambda
isn't copyable because of foo
. Its copy constructor is deleted as a consequence of the fact that the copy constructor of a std::unique_ptr
is deleted.
On the other side, F &&f
accepts both lvalue and rvalue references being it a forwarding reference, as well as const references.
In other terms, if you want to reuse the same lambda as an argument more than once, you cannot if your functions get your object by copy and you must move it for it's not copyable (well, actually you can, it's a matter of wrapping it in a lambda that captures the outer one by reference).
在上面的代码片段中,lambda由于foo而不可复制。由于删除了std::unique_ptr的复制构造函数,它的复制构造函数被删除。另一方面,F &&f接受lvalue和rvalue引用,因为它既是转发引用,也是const引用。在其他方面,如果你想重用相同的λ作为参数不止一次,你不能如果你的函数被拷贝对象,你必须为它不是复制,移动它(实际上可以,重要的是包装在一个λ捕获外一个引用)。
#2
3
As lambda expressions can have their own fields (like classes), copying / using reference can cause different results. Here's simple example:
由于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;
}
Btw if you want to judge it by performance there's actually no difference, lambdas are very small and easy to copy.
顺便说一下,如果你想用性能来判断它实际上没有区别,lambdas非常小而且很容易复制。
Also – if you want to pass lambda as parameter (not a variable that contains it) you should use forwarding reference so it could work.
另外——如果您想将lambda传递为参数(而不是包含它的变量),您应该使用forwarding引用,以便它可以工作。
#1
4
As a possible drawback, note that passing by copy could not work if the lambda isn't copyable. If you can get away with it, passing by copy is just fine.
As an example:
作为一个可能的缺点,请注意,如果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);
}
In the snippet above, lambda
isn't copyable because of foo
. Its copy constructor is deleted as a consequence of the fact that the copy constructor of a std::unique_ptr
is deleted.
On the other side, F &&f
accepts both lvalue and rvalue references being it a forwarding reference, as well as const references.
In other terms, if you want to reuse the same lambda as an argument more than once, you cannot if your functions get your object by copy and you must move it for it's not copyable (well, actually you can, it's a matter of wrapping it in a lambda that captures the outer one by reference).
在上面的代码片段中,lambda由于foo而不可复制。由于删除了std::unique_ptr的复制构造函数,它的复制构造函数被删除。另一方面,F &&f接受lvalue和rvalue引用,因为它既是转发引用,也是const引用。在其他方面,如果你想重用相同的λ作为参数不止一次,你不能如果你的函数被拷贝对象,你必须为它不是复制,移动它(实际上可以,重要的是包装在一个λ捕获外一个引用)。
#2
3
As lambda expressions can have their own fields (like classes), copying / using reference can cause different results. Here's simple example:
由于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;
}
Btw if you want to judge it by performance there's actually no difference, lambdas are very small and easy to copy.
顺便说一下,如果你想用性能来判断它实际上没有区别,lambdas非常小而且很容易复制。
Also – if you want to pass lambda as parameter (not a variable that contains it) you should use forwarding reference so it could work.
另外——如果您想将lambda传递为参数(而不是包含它的变量),您应该使用forwarding引用,以便它可以工作。