专栏首页acoolgiser_zhuanlan[C++11札记]: std::function

[C++11札记]: std::function

在C/C++中函数指针作为一种回调机制被广泛使用,但是函数指针在C++面向对象编程中有些不足,比如无法捕捉上下文。举个例子,使用对象的非静态成员函数作为函数指针就无法做到。

仿函数 在C++11之前,我们在使用STL算法时,通常会使用到一种特别的对象,称为函数对象,或者仿函数(functor),例子如下:

class _functor { public:     int operator()(int x, int y) { return x + y; } };

int main() {     int girls = 3, boys = 4;     _functor totalChild(5, 6);     return totalChild(5, 6); } 简单地说,仿函数就是重新定义了成员函数operator()的一种对象,其使用在代码层面感觉跟函数的使用并无二样,但究其本质却并非函数。

相比函数,仿函数可以拥有初始状态,一般通过class定义私有成员,并在声明对象的时候对其进行初始化。私有成员的状态就成了仿函数的初始状态。声明一个仿函数对象可以拥有多个不同初始状态的实例,因此可以借由仿函数产生多个功能类似却不同的仿函数实例。

#include <iostream> using namespace std;

class Tax { private:     float rate;     int base; public:     Tax(float r, int b) : rate(r), base(b) {}     float operator() (float money) { return (money - base) * rate; } };

int main() {     Tax high(0.40, 30000);     Tax middle(0.25, 20000);     cout << "tax over 3w: " << high(37500) << endl;     cout << "tax over 2w: " << middle(27500) << endl;

    return 0; } std::function 在上一篇文章中我们介绍了C++11中的lambda函数。lambda函数在本质上并非函数,这样导致一个问题:

函数指针不能指向lambda函数,因为lambda函数本质上并非函数。 仿函数和函数指针及lambda函数类型也不相同。 当然上述问题也不是没有解决方法,通过C++模板(template)就可以,std::sort的实现就使用了模板,不论使用函数、仿函数还是lambda函数实现排序算法,均可以传给std::sort。

但是采用模板最大的问题在于编译期展开,头文件会变得很大,编译时间也会很长。

C++11引入std::function更好的解决了这一问题。

std::function可以用于保存并调用任何可调用的东西,比如函数、lambda函数、std::bind表达式、仿函数,甚至是指向对象成员的指针。

std::function简单来说就像是个接口,且能够把符合这个接口的对象(这里对象泛指一切类型,并非面向对象编程中的对象)储存起来,更神奇的是,两个std::function的内容可以交换。

下面的示例演示了将函数指针、lambda函数和std::bind表达式传递给std::function:

int add(int a, int b) { return (a + b); } int sub(int a, int b) { return (a - b); } int mul(int a, int b) { return (a * b); }

class Math { public:     int mod(int a, int b) { return (a % b); } };

int compute(int a, int b, std::function op) { return op(a, b); }

int main() {     compute(1, 2, add);     compute(1, 2, sub);     compute(1, 2, mul);

    compute(1, 2, [](int a, int b) -> int { return (a % b); });

    Math math;     compute(1, 2, std::bind(&Math::mod, &math, std::placeholders::_1, std::placehoders::_2));

    return 0; } 需要指出的是,所谓符合接口,并不需要参数和返回值声明完全一致,只要能够通过隐式转换变成相同类型就可以了。所以std::function

double divide(double a, double b) { return (a / b); }

compute(1, 2, divide); 从上面的例子可以看出,std::function可以应用的范围很广,而且没有模板带来的头文件膨胀问题,非常适合取代函数指针。然而,std::function相较于函数指针,性能上会有一点点损失,如果不是在性能特别关键的场合,还是大胆拥抱C++ 11这一新特性吧!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • three.js 游戏循环 渲染循环

    物体运动还有一个关键点,就是要渲染物体运动的每一个过程,让它显示给观众。渲染的时候,我们调用的是渲染器的render() 函数。代码如下:

    acoolgiser
  • MFC中的下拉框ComboBox使用

    Combo Box (组合框)控件很简单,可以节省空间。从用户角度来看,这个控件是由一个文本输入控件和一个下拉菜单组成的。用户可以从一个预先定义的列表里选择一...

    acoolgiser
  • JS中函数的两种定义方法

    请注意,函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。因此,函数内部通过条件判断和循环可以实现非常复杂的逻辑。

    acoolgiser
  • 数组问题

    输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字...

    大学里的混子
  • 洛谷P2045 方格取数加强版(费用流)

    对于拆出来的每个点,在其中连两条边,一条为费用为点权,流量为1,另一条费用为0,流量为INF

    attack
  • 计算日期(快速幂+打表) - ZOJ 3785

    It's Saturday today, what day is it after11 + 22 + 33 + ... + NN days?

    ACM算法日常
  • 素数相关问题练习 C++

    辗转相除 #include <iostream> using namespace std; int gcb(int a,int b) { if(b==...

    kalifa_lau
  • Search in Rotated Sorted Array

    问题:找出某个元素的位置 朴素的暴力方法 class Solution { public: int search(int A[], int n, int...

    用户1624346
  • POJ 刷题系列:2993. Emag eht htiw Em Pleh

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.n...

    用户1147447
  • 1031 质数环

    1031 质数环  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解 题目描述 Description 一个大小为N(...

    attack

扫码关注云+社区

领取腾讯云代金券