std::function & std::bind

本文深入解析了C++中的函数指针概念,包括声明与使用方法,以及如何利用typedef与decltype进行类型定义。同时,详细介绍了std::function的功能与优势,展示了其在保存不同类型可调用对象方面的灵活性,以及std::bind如何用于函数适配,减少参数传递。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

函数指针简介

函数指针指向某种特定类型,函数的类型由其参数及返回类型共同决定,与函数名无关 。

int callWithMax(int a, int b)//函数定义

 这个函数的返回值是int,传入的两个参数也是int,所以这个函数的类型就是 int(int, int)类型,我们可以声明一个指向该函数的函数指针,声明如下:

int (*p)(int, int)//此时还未初始化

 这样的话这个函数指针就可以指向所有的int(int, int)类型的函数,我们让它指向callWithMax函数。

p = callWithMax;//等同于p = &callWithMax;

这样的话p就可以当作callWithMax函数用了。

源码:

#include<iostream>

int callWithMax(int a, int b){
	return a > b ? a : b;
}

int (*p)(int, int);

int main(){
	p = &callWithMax;
	std::cout << p(1,2);
	return 0; 
}

输出 :

函数指针在c++11中的声明

1. typedef与decltype组合定义函数类型

按如下声明的话,pf就是一个函数类型,它和callWithMax类型相同。decltype()返回传入参数的数据类型。

typedef decltype(callWithMax) pf;

 源码:

#include<iostream>

int callWithMax(int a, int b){
	return a > b ? a : b;
}

typedef decltype(callWithMax) pf;
int main(){
	pf* max;
	max = callWithMax;
	std::cout << max(1,2);
	return 0; 
}

输出:

你也可以直接使用如下直接声明函数指针

typedef decltype(callWithMax)* pf;

这样使用的话直接使用以下声明即可:

 

pf max;
max = callWithMax;

2.使用auto自动匹配函数类型

auto可以直接判断数据类型,因此这种写法最简单

	auto max = callWithMax;

源码:

#include<iostream>

int callWithMax(int a, int b){
	return a > b ? a : b;
}

int main(){
	auto max = callWithMax;
	std::cout << max(1,2);
	return 0; 
}

输出:

 

std::function 

 1.可调用对象

定义:

  • 是一个函数指针;
  • 是一个具有operator()成员函数的类的对象;
  • 可被转换成函数指针的类对象;
  • 一个类成员函数指针;

我们可以看以下三种写法:

int Max(int a, int b){return a > b ? a : b;}//普通函数
auto Max_lambda = [](int a, int b){return a > b ? a : b;}//lambda表达式
//仿函数
class Max_class{
public:
    int operator()(int a, int b){
        return a > b ? a : b;
    }
}

这三种写法都是同一个调用对象类型

int(int, int)

 而std::function就可以保存这个类型

std::function<int(int, int)> m1 = Max;
std::function<int(int, int)> m2 = Max_lambda;
std::function<int(int, int)> m3 = Max_class();

定义格式:std::function<函数类型>。 

std::function 是一个可调用对象包装器,是一个类模板,可以容纳除了类成员函数指针之外的所有可调用对象,它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟它们的执行。

std::function可以取代函数指针的作用,因为它可以延迟函数的执行,特别适合作为回调函数使用。它比普通函数指针更加的灵活和便利。

std::bind

std::bind可以看作为是一个函数适配器,它接收一个可调用对象和它的参数,将其绑定为一个新的参数列表的可调用对象。

  • 将可调用对象和其参数绑定成一个仿函数;
  • 只绑定部分参数,减少可调用对象传入的参数。

对函数使用std::bind 

源码1:

#include<iostream>
/* 引入bind的头文件 */
#include <functional>
/* _1 下标的命名空间 */
using namespace std::placeholders;
double m_div(double a, double b){
	return a / b;
}
int main(){
    /* 给m_div绑定两个参数,第一个参数是函数名,第二个参数是_1也就是一个记号,以后传入的参数将代替这个位置(m_div的第一个参数) ,第三个参数是m_div的第二个参数*/
	auto half = std::bind(m_div,_1,2);
	std::cout << half(10);
	return 0; 
}

输出:

 

上述“auto half = std::bind(m_div,_1,2);”相当与声明了一个新的函数half,它的实现如下:

double m_div(double a/*, double b = 2*/){
	return a / b;
    //return a / 2;
}

源码2:

#include<iostream>
#include <functional>
double m_div(double a, double b){
	return a / b;
}
using namespace std::placeholders;
int main(){
	auto div_ = std::bind(m_div,_1,_2);//标记两个参数
	std::cout << div_(10, 5);
	return 0; 
}

输出:

 

对成员函数使用std::bind

源码:

#include<iostream>
#include <functional>
class Div{
	public:
		double m_div(double a, double b){
			return a / b;
		}
};
using namespace std::placeholders;
int main(){
	Div d;
    //第一个参数必须是&类名::函数名,第二个参数是类的地址,然后是参数列表下标 
	auto helf = std::bind(&Div::m_div, &d,_1,_2);
	std::cout << helf(10, 5);
	return 0; 
}

输出:

 

绑定一个引用参数

默认情况下,bind的那些不是占位符的参数被拷贝到bind返回的可调用对象中。但是,与lambda类似,有时对有些绑定的参数希望以引用的方式传递,或是要绑定参数的类型无法拷贝。(以下代码引用自博客:https://www.jianshu.com/p/f191e88dcc80)

#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <sstream>
using namespace std::placeholders;
using namespace std;

ostream & print(ostream &os, const string& s, char c)
{
    os << s << c;
    return os;
}

int main()
{
    vector<string> words{"helo", "world", "this", "is", "C++11"};
    ostringstream os;
    char c = ' ';
    for_each(words.begin(), words.end(), 
                   [&os, c](const string & s){os << s << c;} );
    cout << os.str() << endl;

    ostringstream os1;
    // ostream不能拷贝,若希望传递给bind一个对象,
    // 而不拷贝它,就必须使用标准库提供的ref函数
    for_each(words.begin(), words.end(),
                   bind(print, ref(os1), _1, c));
    cout << os1.str() << endl;
}
### C++ 中 `std::function` 和 `std::bind` 的用法及区别 #### 定义与基本概念 `std::function` 是一种通用多态函数封装器,可以存储任何可调用对象(如普通函数、lambda 表达式、绑定表达式或其他函数对象)。其灵活性使得它能够作为回调机制的一部分,在事件驱动编程和其他场景下非常有用。 ```cpp #include &lt;functional&gt; #include &lt;iostream&gt; void simpleFunction(int a) { std::cout &lt;&lt; &quot;Value is: &quot; &lt;&lt; a &lt;&lt; &#39;\n&#39;; } int main() { // 创建一个 std::function 对象并赋值给简单函数 std::function&lt;void(int)&gt; f = simpleFunction; f(42); } ``` 另一方面,`std::bind` 提供了一种方式来创建新的可调用对象,这些新对象可以通过固定某些参数或将多个可调用实体组合在一起的方式简化现有可调用目标的接口。通过 bind 可以提前设置部分参数,从而减少后续调用时传递相同参数的需求[^1]。 ```cpp #include &lt;functional&gt; #include &lt;iostream&gt; class MyClass { public: void memberFunc(int i, double d) const { std::cout &lt;&lt; &quot;Integer value: &quot; &lt;&lt; i &lt;&lt; &quot;, Double Value:&quot; &lt;&lt; d &lt;&lt; &quot;\n&quot;; } }; int main(){ using namespace std::placeholders; MyClass obj; // 绑定成员函数到特定实例,并预先设定第一个参数 auto boundMember = std::bind(&amp;MyClass::memberFunc, &amp;obj, _1, 3.14); // 调用已绑定的对象只需要提供剩余未固定的参数即可 boundMember(7); } ``` #### 主要差异点 - **目的不同**: `std::function` 更侧重于作为一个容器去保存各种类型的可调用对象;而 `std::bind` 则专注于调整已有可调用对象的行为模式,比如预设一些输入参数。 - **使用场合的区别**: 当需要定义一个能接受多种不同类型但签名兼容的函数指针的地方时,应该优先考虑使用 `std::function`; 如果想要改变某个具体函数或方法的工作方式,则可以选择 `std::bind`. - **性能考量**: 在大多数情况下,直接使用 lambda 表达式可能比使用 `std::bind` 效率更高,因为后者可能会引入额外的小型分配开销以及间接层。然而对于复杂情况下的参数绑定操作来说,`std::bind` 还是有它的优势所在[^2].
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值