有关C ++中Lambda函数的所有信息:从C ++ 11到C ++ 17
Lambda函数是C ++ 11中引入的Modern C ++的一个直观概念,因此在Internet上有关Lambda函数教程的文章已经很多。但是,仍然有一些难以言喻的东西(例如IIFE,lambda类型等),没人谈论。因此,在这里,我不仅要向您展示C ++中的lambda函数,而且还将介绍Lambda的内部工作方式以及Lambda的其他方面。本文的标题有点误导。因为lambda并不总是合成为函数指针。这是一个表达式(恰好是唯一的闭包)。但是为了简单起见,我一直这样做。所以从现在开始,我将互换使用lambda函数和表达式./ !:顺便说一句,这是我博客中的交叉文章.lambda函数是什么?lambda函数是代码的简短片段
- 不值得命名(未命名,匿名,可处理等),无论您如何称呼它,
- 而且也不会重复使用。
换句话说,它只是语法糖。lambda函数的语法定义为:(捕获列表)(参数)->返回类型
{
方法定义
}
- 通常,编译器会评估lambda函数本身的返回类型。因此,我们不需要显式指定尾随返回类型,即-> return-type。
- 但是在某些复杂的情况下,编译器无法推断出返回类型,因此我们需要指定返回类型。
为什么我们应该使用lambda函数?
- C ++包括许多有用的通用函数,例如std :: for_each,它们很方便。不幸的是,它们使用起来也很麻烦,特别是如果您想应用的函子是特定功能所独有的。考虑以下代码作为示例:
struct print
{
void operator()(int element)
{
cout << element << endl;
}
};
int main(void)
{
std :: vector
std :: for_each(v.begin(),v.end(),print());
返回0;
}
- 如果您只在那个特定位置使用一次print,那么写一整堂课只是为了完成一些琐碎而一次性的事情似乎就太过分了。
- 但是,对于这种情况,内联代码将更合适,这可以通过如下的lambda函数来实现:
std :: for_each(v.begin(),v.end(),()(int元素){cout << element << endl;}); lambda函数如何在内部工作?(&i)(){std :: cout <<我;}
//等价于
struct匿名
{
int&m_i;
匿名(int&i):m_i(i){}
内联自动运算符()()const
{
std :: cout << i;
}
};
- 编译器为每个lambda函数生成上述唯一的闭包。最后,秘密揭晓了。
- 捕获列表将成为闭包中的构造函数参数,如果将参数捕获为值,则在闭包中创建相应的类型数据成员。
- 此外,您可以在lambda函数参数中声明变量/对象,该参数将成为调用操作符(即operator())的参数。
使用Lambda函数的好处
- 零成本抽象。是! 你没看错。lambda不会花费您的性能,也不会像普通功能那样快速。
- 此外,代码变得紧凑,结构化和表达力强。
通过引用/ valueint学习lambda expressionCapture main()
{
int x = 100,y = 200;
自动打印=(&){//通过引用
std :: cout 捕获对象<< __PRETTY_FUNCTION__ <<“:” << x <<“,” << y << std :: endl;
};
打印();
返回0;
}输出:main()::
- 在上面的示例中,我在捕获列表中提到了&。它捕获变量x和y作为参考。类似地,=表示按值捕获,这将在闭包内创建相同类型的数据成员,并进行复制分配。
- 请注意,参数列表是可选的,如果不将参数传递给lambda表达式,则可以省略空括号。
Lambda捕获列表
- 下表显示了相同的不同用例:
将lambda作为参数模板传递
void f(Functor functor)
{
std :: cout << __PRETTY_FUNCTION__ << std :: endl;
}
/ *或者,您也可以使用此
void f(std :: function
{
std :: cout << __PRETTY_FUNCTION__ << std :: endl;
}
* /
int g(){static int i = 0; 返回我++; }
int main()
{
auto lambda_func =(i = 0)()可变{return i ++; };
f(lambda_func); //通过lambda
f(g); //通过函数
} Output:Function类型:void f(Functor)(with Functor = main()::
Function Type:void f(Functor)(with Functor = int(*)(int) )
- 您也可以将lambda函数作为参数传递给其他函数,就像我上面编写的普通函数一样。
- 如果您注意到了,这里我在捕获列表中声明了变量i,它将成为数据成员。结果,每次调用lambda_func时,它将被返回并递增。
在lambda或此指针类中捕获成员变量示例
{
public:
Example():m_var(10){}
void func()
{
(=)(){std :: cout << m_var << std :: endl; }(); // IIFE
}
private:
int m_var;
};
int main()
{
示例e;
e.func();
}
- 也可以使用(this),(=)或(&)捕获该指针。在任何这些情况下,都可以像在常规方法中一样访问类数据成员(包括私有数据)。
- 如果您看到lambda表达式行,我在lambda函数声明的末尾使用了extra(),该函数在声明之后就用来对其进行调用。它称为IIFE(立即调用函数表达式)。
C ++ lambda函数类型通用lambdaconst auto l =()(auto a,auto b,auto c){};
// //等效于
struct匿名
{
模板
auto operator()(T0 a,T1 b,T2 c)const
{
}
};
- C ++ 14中引入的通用lambda可以使用自动说明符捕获参数。
可变参数泛型lambdavoid print(){}
模板
void print(const First&first,Rest && … args)
{
std :: cout << first << std :: endl;
打印(参数…);
}
int main()
{
auto variadic_generic_lambda =()(auto … param){
print(param …);
};
variadic_generic_lambda(1,“ lol”,1.1);
}
- 具有可变参数包的Lambda在许多情况下都非常有用,例如调试,使用不同数据输入的重复操作等。
可变λ函数
- 通常,lambda的函数调用运算符是const-by-value,这意味着,如果您要捕获按值捕获的任何内容,则lambda需要使用可变关键字。
()()可变{}
//等价于
struct匿名
{
auto operator()()//调用运算符
{
}
};
- 上面我们已经看到了一个示例。我希望你注意到了。
Lambda作为函数指针
#include < iostream> #include
int main()
{
auto funcPtr = +(){};
static_assert(std :: is_same
}
- 您可以通过如上所述添加+ infront来强制编译器将lambda生成为函数指针而不是闭包。
高阶返回lambda函数const auto less_than =()(auto x){
return(x)(auto y){
return y
};
};
int main(void)
{
auto less_than_five = less_than(5);
std :: cout << less_than_five(3)<< std :: endl;
std :: cout << less_than_five(10)<< std :: endl;
返回0;
}
- 更进一步,lambda函数还可以返回另一个lambda函数。这将为代码的自定义,代码可表达性和可压缩性打开无限可能的门(顺便说一句,没有这样的词)。
constexpr lambda表达式
- 从C ++ 17开始,可以将lambda表达式声明为constexpr。
constexpr auto sum =()(const auto&a,const auto&b){返回a + b; };
/ *
等效于
constexpr struct匿名
{
模板
constexpr auto operator()(T1 a,T2 b)const
{
返回a + b;
}
};
* /
constexpr int答案= sum(10,10);
- 即使您未指定constexpr,但函数调用运算符恰好满足所有constexpr函数的要求,无论如何它还是constexpr。
结束语我希望你喜欢这篇文章。我试图用几个简单的小例子来介绍关于lambda的大多数复杂问题。考虑到代码的可表达性和易维护性,无论您想到什么,都应该使用lambda,就像可以在自定义删除器中将其用于智能指针以及大多数STL算法一样。