C++20学习笔记——头等函数(Lambda闭包)

本文详细介绍了C++20中的头等函数,包括函数指针、函数对象、lambda表达式及其应用。重点讨论了lambda表达式的定义、捕获方式、泛型使用,以及std::function模板在处理不同类型的头等函数中的重要作用。通过实例展示了头等函数在高阶函数、回调函数和类型别名中的使用,强调了它们在函数式编程和提高代码可读性方面的重要性。
摘要由CSDN通过智能技术生成

头等函数

在计算机科学中,如果编程语言允许将函数当作其他任何变量,则该语言提供了头等函数。

一、函数指针

函数指针是一个变量,可储存函数的地址,在程序执行的不同时间可指向不同的函数。

1.1 定义函数指针

示例:

long (*fun_ptr)(long*, int);

上述代码定义了一个函数指针,它可以储存参数为long和int、返回值为long的函数地址。
但要注意的是不能将包括了
fun_ptr的圆括号去掉,如果去掉该语句将被解释为返回long指针类型的函数。

如上,函数指针的定义一般形式如下:

return_type (*pointer_name)(parameter_types);

当然,在学了auto以后我们可以很容易想到使用auto去定义函数指针会方便得多:

auto fun_ptr = func_name;

我们也可以添加 * 号来强调变量是指针的事实:

auto* fun_ptr = func_name;

这样,我们就可以将fun_ptr指向任何与type_name拥有一样类型的参数与返回类型的函数了。
以下写法与上述效果等效;

auto fun_ptr = func_name;
auto fun_ptr = &func_name;
auto* fun_ptr = func_name;
auto* fun_ptr = &func_name;

故而很多人建议始终添加取址运算符,因为这样能够增加代码的可读性。
当我们将函数指针指向一个确定的函数只会,我们就可以将其当成和原函数一样的方法取使用,比如:

double myFunc(int val)
{
   
	double result = static_cast<double>(val)*std::numbers::pi;
	return result;
}
int main()
{
   
	auto* ptr2 = &myFunc;
	std::cout << myFunc(10)<<std::endl;     //out:31.4159
	std::cout << ptr2(10) << std::endl;     //out:31.4159
}

1.2 高阶函数的回调函数

作为实参传递给另一个函数的函数称为“回调函数”(callback function);接收另一个函数作为实参的函数称为“高阶函数”(higher-order function)。

template<typename T>
const T* findOptimum(const std::vector<T>& values, bool (*compare)(const T&, const T&))		//这个函数模板与sort很类型,特别是第二个参数,其作用与sort里的emp参数是一致的
{
   
	if (values.empty()) return nullptr;		
	const T* optimum = &values[0];
	for(size_t i {
   1};i<values.size();i++)
	{
   
		if (compare(values[i], *optimum))
			optimum = &values[i];
	}
	return optimum;
}

bool less(const int& one,const int& other)
{
   
	return one < other;
}

template<typename T>
bool greater(const T& one, const T& other)
{
   
	return one > other;
}

bool longer(const std::string& one,const std:: string& other)
{
   
	return one.length() > other.length();
}

int main()
{
   
	std::vector<int> numbers{
    91,18,92,22,13,43 };
	std::cout << "min : " << *findOptimum(numbers, less) << std::endl;
	std::cout << "max : " << *findOptimum(numbers, greater) << std::endl;

	std::vector<std::string> names{
    "Moe","Larry","Shemp","Curly","Joe","Curly Joe" };
	std::cout << *findOptimum(names, greater<std::string>) << std::endl;
	std::cout << "Longest name : " << *findOptimum(names, longer);
}

输出:

min : 13
max : 92
Shemp
Longest name : Curly Joe

从上面的例子我们就可以看出使用函数指针的好处了:当我们想寻找最大或最小值时,如果我们不适用函数指针传参,那么我们就必须因为比较逻辑的不同而手动分别实现两种函数重载,但是如果我们使用函数指针传参,那么比较逻辑本身就是其中的一个参数,那么我们就不必使用函数重载,这很好的履行了我们之前说所的"DRY"原则。


注意:除了作为高阶函数的实参,头等回调函数还有其他许多用途。在日常的面向对象编程中,也会经常用到回调函数。对象常常在其成员变量中储存回调函数。调用这种回调函数可实现多种用途。它们可作为对象的某个成员函数实现的逻辑中可由用户配置的步骤,也可以用来告诉其他对象发生了某个事件。各种形式的回调函数可辅助各种标准的面向对象技术和模式,最显著的可能是经典Obsever模式的变体。


1.3 函数指针的类型别名

当然,很多时候我们可以使用auto来解决函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值