C++ 中的 Lambda 表达式与函子
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4686507/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Lambda Expression vs Functor in C++
提问by Chan
I wonder where should we use lambdaexpression over functor in C++. To me, these two techniques are basically the same, even functor is more elegant and cleaner than lambda. For example, if I want to reuse my predicate, I have to copy the lambda part over and over. So when does lambda really come in to place?
我想知道在 C++ 中我们应该在哪里使用lambda表达式而不是函子。对我来说,这两种技术基本相同,甚至 functor 也比lambda更优雅、更简洁。例如,如果我想重用我的谓词,我必须一遍又一遍地复制 lambda 部分。那么 lambda 什么时候真正到位呢?
采纳答案by Edward Strange
1) It's trivial and trying to share it is more work than benefit.
1)它是微不足道的,试图分享它更多的是工作而不是利益。
2) Defining a functor simply adds complexity (due to having to make a bunch of member variables and crap).
2)定义一个函子只会增加复杂性(因为必须创建一堆成员变量和废话)。
If neither of those things is true then maybe you should think about defining a functor.
如果这些都不是真的,那么也许你应该考虑定义一个函子。
Edit: it seems to be that you need an example of when it would be nice to use a lambda over a functor. Here you go:
编辑:您似乎需要一个示例,说明何时在函子上使用 lambda 会更好。干得好:
typedef std::vector< std::pair<int,std::string> > whatsit_t;
int find_it(std::string value, whatsit_t const& stuff)
{
auto fit = std::find_if(stuff.begin(), stuff.end(), [value](whatsit_t::value_type const& vt) -> bool { return vt.second == value; });
if (fit == stuff.end()) throw std::wtf_error();
return fit->first;
}
Without lambdas you'd have to use something that similarly constructs a functor on the spot or write an externally linkable functor object for something that's annoyingly trivial.
如果没有 lambda,您将不得不使用类似地在现场构造函子的东西,或者为一些烦人的琐碎事情编写一个外部可链接的函子对象。
BTW, I think maybe wtf_error is an extension.
顺便说一句,我想也许 wtf_error 是一个扩展。
回答by Steve Jessop
A lambda expression creates an nameless functor, it's syntactic sugar.
一个 lambda 表达式创建了一个无名的函子,它是语法糖。
So you mainly use it if it makes your code look better. That generally would occur if either (a) you aren't going to reuse the functor, or (b) you are going to reuse it, but from code so totally unrelated to the current code that in order to share it you'd basically end up creating my_favourite_two_line_functors.h
, and have disparate files depend on it.
所以你主要是在它让你的代码看起来更好的情况下使用它。如果(a)您不打算重用函子,或者(b)您打算重用它,但是来自与当前代码完全无关的代码,为了共享它,您基本上会发生这种情况最终创建my_favourite_two_line_functors.h
,并有不同的文件依赖于它。
Pretty much the same conditions under which you would type any line(s) of code, and not abstract that code block into a function.
几乎与您键入任何代码行的条件相同,而不是将该代码块抽象为函数。
That said, with range-for statements in C++0x, there are some places where you would have used a functor before where it might well make your code look better now to write the code as a loop body, not a functor or a lambda.
也就是说,对于 C++0x 中的 range-for 语句,在某些地方您之前会使用函子,现在将代码编写为循环体,而不是函子或拉姆达。
回答by Will Bradley
Lambdas are basicallyjust syntactic sugar that implement functors (NB: closures are not simple.) In C++0x, you can use the auto keyword to store lambdas locally, and std::function will enable you to store lambdas, or pass them around in a type-safe manner.
Lambda基本上只是实现函子的语法糖(注意:闭包并不简单。)在 C++0x 中,您可以使用 auto 关键字在本地存储 lambda,而 std::function 将使您能够存储 lambda,或传递它们以类型安全的方式围绕。
Check out the Wikipedia article on C++0x.
回答by Martin York
Small functions that are not repeated.
不重复的小功能。
The main complain about functors is that they are not in the same place that they were used. So you had to find and read the functor out of context to the place it was being used in (even if it is only being used in one place).
对函子的主要抱怨是它们不在使用它们的地方。因此,您必须在使用它的地方脱离上下文查找和读取函子(即使它只在一个地方使用)。
The other problem was that functor required some wiring to get parameters into the functor object. Not complex but all basic boilerplate code. And boiler plate is susceptible to cut and paste problems.
另一个问题是函子需要一些连线才能将参数传入函子对象。不复杂,但所有基本样板代码。并且锅炉板容易出现剪切和粘贴问题。
Lambda try and fix both these. But I would use functors if the function is repeated in multiple places or is larger than (can't think up an appropriate term as it will be context sensitive) small.
Lambda 尝试修复这两个问题。但是如果函数在多个地方重复或者大于(无法想出一个合适的术语,因为它会是上下文敏感的)小,我会使用函子。
回答by edW
lambda and functor have context. Functor is a class and therefore can be more complex then a lambda. A function has no context.
lambda 和函子有上下文。Functor 是一个类,因此可能比 lambda 更复杂。函数没有上下文。
#include <iostream>
#include <list>
#include <vector>
using namespace std;
//Functions have no context, mod is always 3
bool myFunc(int n) { return n % 3 == 0; }
//Functors have context, e.g. _v
//Functors can be more complex, e.g. additional addNum(...) method
class FunctorV
{
public:
FunctorV(int num ) : _v{num} {}
void addNum(int num) { _v.push_back(num); }
bool operator() (int num)
{
for(int i : _v) {
if( num % i == 0)
return true;
}
return false;
}
private:
vector<int> _v;
};
void print(string prefix,list<int>& l)
{
cout << prefix << "l={ ";
for(int i : l)
cout << i << " ";
cout << "}" << endl;
}
int main()
{
list<int> l={1,2,3,4,5,6,7,8,9};
print("initial for each test: ",l);
cout << endl;
//function, so no context.
l.remove_if(myFunc);
print("function mod 3: ",l);
cout << endl;
//nameless lambda, context is x
l={1,2,3,4,5,6,7,8,9};
int x = 3;
l.remove_if([x](int n){ return n % x == 0; });
print("lambda mod x=3: ",l);
x = 4;
l.remove_if([x](int n){ return n % x == 0; });
print("lambda mod x=4: ",l);
cout << endl;
//functor has context and can be more complex
l={1,2,3,4,5,6,7,8,9};
FunctorV myFunctor(3);
myFunctor.addNum(4);
l.remove_if(myFunctor);
print("functor mod v={3,4}: ",l);
return 0;
}
Output:
输出:
initial for each test: l={ 1 2 3 4 5 6 7 8 9 }
function mod 3: l={ 1 2 4 5 7 8 }
lambda mod x=3: l={ 1 2 4 5 7 8 }
lambda mod x=4: l={ 1 2 5 7 }
functor mod v={3,4}: l={ 1 2 5 7 }
回答by Vishal Chovatiya
First, i would like to clear some clutter here.
首先,我想在这里清除一些混乱。
There are two different things
有两种不同的东西
- Lambda function
- Lambda expression/functor.
- Lambda 函数
- Lambda 表达式/函子。
Usually, Lambda expression i.e. [] () {} -> return-type
does not always synthesize to closure(i.e. kind of functor). Although this is compiler dependent. But you can force compiler by enforcing +
sign before []
as +[] () {} -> return-type
. This will create function pointer.
通常,Lambda 表达式 ie[] () {} -> return-type
并不总是合成为闭包(即一种函子)。虽然这取决于编译器。但是您可以通过+
在[]
as之前强制执行符号来强制编译器+[] () {} -> return-type
。这将创建函数指针。
Now, coming to your question. You can use lambda repeatedly as follows:
现在,来回答你的问题。您可以按如下方式重复使用 lambda:
int main()
{
auto print = [i=0] () mutable {return i++;};
cout<<print()<<endl;
cout<<print()<<endl;
cout<<print()<<endl;
// Call as many time as you want
return 0;
}
You should use Lambda wherever it strikes in your mind considering code expressiveness & easy maintainability like you can use it in custom deleters for smart pointers & with most of the STL algorithms.
考虑到代码表现力和易于维护性,您应该在任何想到 Lambda 的地方使用它,就像您可以在自定义删除器中用于智能指针和大多数 STL 算法一样。
If you combine Lambda with other features like constexpr
, variadic template parameter pack
or generic lambda
. You can achieve many things.
如果您将 Lambda 与其他功能(如constexpr
、variadic template parameter pack
或generic lambda
. 你可以实现很多事情。
You can find more about it here
回答by Tony Delroy
Conceptually, the decision of which to use is driven by the same criterion as using a named variable versus a in-place expression or constant...
从概念上讲,决定使用哪个是由使用命名变量与就地表达式或常量相同的标准驱动的......
size_t length = strlen(x) + sizeof(y) + z++ + strlen('allocate(strlen(x) + sizeof(y) + z++ + strlen('##代码##'));
');
...
allocate(length);
std::cout << length;
...here, creating a length variable encourages the program to consider it's correctness and meaning in isolation of it's later use. The name hopefully conveys enough that it can be understood intuitively and independently of it's initial value. It then allows the value to be used several times without repeating the expression (while handling z
being different). While here...
...在这里,创建一个长度变量鼓励程序考虑它的正确性和意义,并与以后的使用隔离开来。该名称希望能够传达足够的信息,以便可以直观地理解它,并且独立于它的初始值。然后它允许多次使用该值而不重复表达式(同时处理z
不同)。虽然在这里...
...the total code is reduced and the value is localised at the point it's needed. The only thing to "carry forwards" from a reading of this line is the side effects of allocation and increment (z), but there's no extra local variable with scope or later use to consider. The programmer has to mentally juggle less state while continuing their analysis of the code.
...减少了总代码,并将值定位在需要的地方。从这一行的阅读中“结转”的唯一事情是分配和增量 (z) 的副作用,但没有额外的具有作用域或以后使用的局部变量需要考虑。程序员在继续分析代码的同时,必须在精神上处理较少的状态。
The same distinction applies to functions versus inline statements. For the purposes of answering your question, functors versus lambdas can be seen as just a particular case of this function versus inlining decision.
同样的区别适用于函数和内联语句。为了回答您的问题,函子与 lambdas 可以被视为此函数与内联决策的一个特例。
回答by Lou Franco
As you pointed out, it works best when you need a one-off and the coding overhead of writing it out as a function isn't worth it.
正如您所指出的,当您需要一次性使用并且将其作为函数编写的编码开销不值得时,它的效果最佳。