【C++】函数封装与绑定

  • ~2.80K 字
  1. 1. 函数封装与绑定
    1. 1.1. std::function
    2. 1.2. std::mem_fn
    3. 1.3. std::bind

函数封装与绑定

std::function

std::function是一个通用的多态函数封装器,用于将可调用对象进行封装

语法function<R(Args...)> fname = target;

其中R为返回类型,括号内为参数类型

进行类成员函数封装时,括号内第一个参数是类引用,第二个开始才是参数类型

也可以进行类成员变量的引用

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <functional>
double mul(double a, double b){
return a*b;
}
int main(){
// 将mul的地址保存到f1对象中
std::function<double(double,double)> f1 = mul;
// 通过重载调用运算符来调用mul函数
double res = f1(1.1,2.3);
std::cout << res << std::endl;
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <functional>
struct Linear{
Linear(float k, float b):k_(k),b_(b) {}
float f(float x) {return k_* x+b_; }
float k_, b_;
};

int main(){
std :: function<float(Linear&, float)> mf = &Linear::f;
Linear l(1.2,2.3);
float res = mf(l,5);
std :: cout << res << std :: endl;
std :: function<float(Linear&)> k = &Linear :: k_;
std :: cout << k(l) << std :: endl;
}

std::function实现了类型擦除:即通过单个通用接口类使用各种具体类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <functional>
#include <map>

double add(double a, double b){
return a+b;
}
struct substract{
double operator()(double a, double b){return a-b;}

};

int main(){
std::map<char, std::function<double(double,double)>>cal{
{'+', add},
{'-', substract()},
{'*', [](double a, double b)->double{return a*b;}}
};
std::cout <<cal['+'](12.0,13)<<std::endl;
std::cout <<cal['-'](13.0,6.2)<<std::endl;
std::cout <<cal['+'](2.3,3.2)<<std::endl;
}

可以看到,通过std::function可以把完全不同的类型按同一个接口统一封装一个类型来使用

std::mem_fn

封装类成员可以直接使用std::mem_fn,返回一个可调用的包装器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <functional>

struct foo{
double w;
double cal(double a, double b){return 2*a+w*b;}
foo& operator+=(double a){
w+=a;
return *this;
}
void print(){
std::cout<<"w="<<w<<std::endl;
}
};

int main(){
foo f{1.0};
auto memfn = std::mem_fn(&foo::cal);
double res = memfn(f, 2.0, 3.0);
std::cout <<"res="<<res<<std::endl;

auto op = std::mem_fn(&foo::operator+=);
auto f2 = op(f,2.0);
f2.print();
}

std::bind

用于生成一个函数对象,调用该包装器时相当于调用他所包装的函数或者对象f

可以将给定的函数和参数进行绑定,调用时直接使用对应函数与参数

其中,参数可以用std::placeholders占位符占位(_1,_2…),在调用包装器时可以指定传入参数

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <functional>
using namespace std::placeholders;
int sum(int a, int b, int c){
std::cout <<"a="<<a<<", b="<<b<<", c="<<c;
return a+b+c;
}

int main(){
auto f = std::bind(sum, 1, _1, 3);
int res = f(5);
std::cout<<", res="<<res<<std::endl;
}

注意,如果直接用变量作为bind绑定,绑定后修改变量不会影响结果,因为是用值传入的

如果想用引用传入,使用cref()函数,用于返回一个变量的引用封装器s

赞助喵
非常感谢您的喜欢!
赞助喵