模板类std::function<T>的由来

目录

00.背景

01.模板类 //有的地方叫函数模板类,没必要啊,容易引起歧义

02.包装普通函数//静态自由函数是同理的

03.包装静态成员函数

04.包装实例的无参成员函数

06.利用lambda函数包装上述实例的'有参成员函数'

07.总结


00.背景

    笔者在使用C++开发的时候产生过一个想法:能不能获得成员函数的地址,转为函数指针进行操作呢?
    尝试1:获取静态成员函数的首地址

class Math
{
public:
	static int min(int a, int b){
		return a>=b ? b : a;
	}
};

int main()
{
	auto fPtr = &Math::min; //企图获取一个函数指针
	cout << (*fPtr)(10, 20) << endl; //ok! 这么写容易暴露了C语言的出身,哈哈
	return 0;
}


    尝试2:获取访问内存的普通成员函数的地址

class Math
{
public:
	int min(){
		return num1>=num2 ? num2 : num1;
	}
	
	int num1 {10};
	int num2 {20};
};

int main()
{
	auto fPtr = &Math::min; //error! 企图获取一个函数指针
	
	Math *objPtr = nullptr;
	auto a = objPtr->min; //error! 企图获取一个空对象的方法
	cout << (*a)() << endl; //error! 语法糖! 当心存敬畏,勿用,无用,忘掉它!
	return 0;
}


    其实,上面2次尝试有点不讲武德,没准备好构造函数就蛮干!只要类封装了数据,上面的尝试注定失败;
    类是数据和方法的封装集合,脱离数据使用方法就应该使用自由函数!而不是成员函数!
    那么正确的获取'某个实例的成员函数de地址并在适当的时候调用'应该怎么写呢?//为什么有这种需求?这个要从闭包说起

 

01.模板类 //有的地方叫函数模板类,没必要啊,容易引起歧义


    声明形式:

    template <class T> function;     // undefined
    template <class Ret, class... Args> class function<Ret(Args...)>; //看不懂没关系,看实例


    定义:std::function是一个封装了特定方法和数据的'模板类',用于记录运行时实例的状态及函数;
    作用:
        1> 形成闭包;//什么是闭包,我已经透露了!
        2> 冒充函数指针欺骗小白;//简言之,不该用的时候用,就是装逼!
    

02.包装普通函数//静态自由函数是同理的

void normalFunc(int a)
{
	cout << "normalFunc()" << a << endl;
	return;
}

int main()
{
	std::finction<void (int)> fun1 = normalFunc;
	fun1(10);
	return 0;
}

 

03.包装静态成员函数

class Math
{
public:
	static int min(){
		return num1>=num2 ? num2 : num1;
	}
	static int num1;
	static int num2;
};

int Math::num1 = 5; //静态成员变量的类外初始化
int Math::num2 = 10; //静态成员变量的类外初始化

int main()
{
	std::function<int ()> obj = &Math::min; //企图获取一个函数指针
	cout << obj() << endl; //ok! 再不要写(*0bj)(),obj是一个模板类实例,加*号是说不通的
	return 0;
}

 

04.包装实例的无参成员函数

class Math
{
public:
	Math(int a, int b): num1(a), num2(b){}
	int min()
	{
		return num1>=num2 ? num2 : num1;
	}
	int num1;
	int num2;
};

int main()
{
	Math m(10, 20);
	//std::function<int()> f = &m.min; //error! 只获取实例的方法不被允许,尽管意义上说得通
	//std::function<int()> f = &Math::min; //error! 针对那个实例没有做说明
	std::function<int()> f = bind(&Math::min, &m);
	cout << f() << endl; //error! 非法访问内存
	return 0;
}

    
05.包装实例的'有参成员函数'

class Math
{
public:
	
	int min(int a, int b)
	{
		return a>=b ? b : a;
	}
};

int main()
{
	Math m;
	//std::function<int(int, int)> f = &m.min; //error! 只获取实例的方法不被允许,尽管意义上说得通
	//std::function<int(int, int)> f = &Math::min; //error! 针对那个实例没有做说明
	std::function<int(int, int)> f = bind(&Math::min, &m, placeholders::_1, placeholders::_2);
	cout << f(10, 20) << endl; //error! 非法访问内存
	return 0;
}

 

06.包装lambda函数 //最常用

class Math
{
public:
	
	int min(int a, int b)
	{
		return a>=b ? b : a;
	}
};

int main()
{
	Math m;
	//std::function<int(int, int)> f = &m.min; //error! 只获取实例的方法不被允许,尽管意义上说得通
	//std::function<int(int, int)> f = &Math::min; //error! 针对哪个实例没有作说明
	std::function<int(int, int)> f = [&](int x, int y)->int{ return m.min(x, y);}; //只能用捕获引用
	cout << f(10, 20) << endl; //error! 非法访问内存
	return 0;
}

 

07.总结

    前面的示例还好理解,但是到了04、05、06就有点费劲了,为什么呢?这里再强调几点:
    1)单独获取类的成员函数而不获取成员变量,这种操作违背了C++的封装思想,除非这个成员函数是static的;
    2)单独获取一个实例的成员函数无论如何是不能通过的,要获取就要带捕获成员变量的方式一同获取;
    3)关于函数std::bind()和lambda函数需要先去学习后再来搞懂,才能真正理解这3者的关系;
    4)模板类std::function()还可以包装函数对象、模板函数,但本质都是一样的。//封装数据及方法到一个实例


    

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值