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