函数指针与 std::function 简介

​ 在c/c++实际编程中,使用函数指针/function对象有时候可以让我们的代码更加简洁条理,尤其存在对同一对象多种不同的处理方案时,使用函数指针/function对象结合std::map等数据结构,会有效减少代码中臃肿的if...else语句。

​ 一般情况下,代码中的可调用对象可大致概括为如下几种形式,另外仍有诸如仿函数对象等存在,其有自身调用特征的特殊性,但是又符合一般调用的法则,所以下文只针对个人常见常用的几种可调用对象。

void ordinary_funtion(int) {
	std::cout << "ordinary function ..." << std::endl;
}

class object {
public:
	object() = default;
	~object() = default;
public:
	void non_static_member(int) {
		std::cout << "non static member ..." << std::endl;
	}
	static void static_member(int) {
		std::cout << "static member ..." << std::endl;
	}
};

​ 为了凸显一般性,每个函数我都加入了一个匿名的int参数,对于普通函数来说,定义与调用方法比较直观。

// u can use function pointer as typedef void(*function_pointer)(int);
// but we can use auto in place of explicit definition of a function pointer
auto ordinary_funtion_pointer = ordinary_funtion;
std::function<void(int)> ordinary_funtion_binder_1 = ordinary_funtion;
std::function<void(int)> ordinary_funtion_binder_2 = std::bind(ordinary_funtion, std::placeholders::_1);

​ 上方的三种定义方法可以使用相同的调用方法。

ordinary_funtion_pointer(0);
ordinary_funtion_binder_1(0);
ordinary_funtion_binder_2(0);

​ 对于类的静态成员函数,在c++对象模型上其独立于类的某一个对象,所以其定义与调用方式也比较直观。同样,std::function对象有两种定义方式,调用方式与普通函数一致,如下。

// definition
auto static_member_pointer = &object::static_member;
std::function<void(int)> static_member_binder_1 = &object::static_member;
std::function<void(int)> static_member_binder_2 = std::bind(&object::static_member, std::placeholders::_1);
// call
static_member_pointer(0);
static_member_binder_1(0);
static_member_binder_2(0);

​ 由c++对象模型,类的非静态成员是跟随类的特定对象绑定的,由于其在调用过程中,可能使用类的私有/共有``成员变量/函数,所以在定义或者调用过程中需要给某个对象的信息,而std::function对象的定义方式可以分为(不)/包含对象信息,随着定义方式的不同,调用方式也会相应的不同。同时,函数指针的调用也可以分别值/指针调用,这个时候代码看起来就有点别扭了。

object o_value;
auto o_pointer = new object { };

auto non_static_member_pointer = &object::non_static_member;
std::function<void(object&, int)> non_static_member_binder_1 = &object::non_static_member;
std::function<void(int)> non_static_member_binder_2 = std::bind(&object::non_static_member, &o, std::placeholders::_1);
std::function<void(object&, int)> non_static_member_binder_3 = std::bind(&object::non_static_member, std::placeholders::_1, std::placeholders::_2);

​ 函数指针的定义与之前的定义方式相同,但是std::function对象的定义可选择构造时是否包含对象信息,相应的std::function对象的定义也有所不同,如果已经包含对象地址信息的话,可将对象类型定义为std::function,否则的话,就需要将对象类型定义为std::function,这里的&可以写为*。根据定义的时对象的类型,调用时也需要给定匹配的参数类型。

// function pointer
(o_value.*non_static_member_pointer)(0);
(o_pointer->*non_static_member_pointer)(0);
// std::function
non_static_member_binder_1(o, 0);
non_static_member_binder_2(0);
non_static_member_binder_3(o, 0);

​ 在编程中有件事情令我苦恼,当使用std::mapstd::vector或其他容器的时候。虽然有些操作的物理意义接近或基本相同,但却并不一定所有的函数都有同样的输入参数,当然如果差距不大的话,可以加入一些dummy parameter,有些情况,输入参数差别太大的时候,强行加入参数会导致代码极其丑陋,这个问题我现在还没有思路,等解决之后给大家分享。

reference

C++11 std::function 深度剖析
知乎:如何使用std::function指向类的成员函数

你可能感兴趣的:(C++,c++)