C++ 11 STL | functional 标准库

最近正好用到了这个,就顺便总结下吧。

C++ 11 引入了函数对象标准库 <functional>,里面包含各种内建的函数对象以及相关的操作函数,非常方便。这里总结一下 std::functionstd::bind 的相关用法。

Callable type

Callable type 指可以像调用函数一样被调用的对象或函数,包括:

  • std::function
  • std::bind
  • std::result_of
  • std::thread::thread
  • std::call_once
  • std::async
  • std::packaged_task
  • std::reference_wrapper

根据 C++ 17 Standard,所有 Callable type 都可以通过 std::invoke 方法进行显式调用

std::function

std::function类模板是一种通用的函数包装器,它可以容纳所有可以调用的对象(Callable),包括 函数函数指针Lambda表达式bind表达式、成员函数及成员变量或者其他函数对象。通过 std::function 可以储存、拷贝或调用 Callable 对象。它的模板参数如下:

1
2
template< class R, class... Args >
class function<R(Args...)>

使用时,模板参数与要存储的函数参数一致即可,下面是一些例子:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <functional>
double f(int x, char y, double z) {
return x + y + z;
}
void print_num(int num) {
std::cout << num << std::endl;
}
struct Dog {
int id;
explicit Dog(int id): id(id) {}
void print_add(int i) const {
std::cout << id + i << std::endl;
}
};
class PrintString {
public:
void operator()(std::string&& s) const {
std::cout << s << std::endl;
}
};
int main(int argc, char **argv) {
// common function
std::function<void(int)> func_display_num = print_num;
func_display_num(9);
// common function
std::function<double(int, char, double)> func_display = f;
std::cout << func_display(3, 'a', 1.7) << "\n";
// lambda expression
std::function<void(const char*)> lbd_dsp_str = [](const char *s) {std::cout << s << std::endl;};
lbd_dsp_str("Scala");
// bind expression
auto func_num_bind = std::bind(&f, std::placeholders::_1, 'c', 2.4);
std::cout << func_num_bind(24) << "\n";
// function object
std::function<void(std::string&&)> func_obj_print = PrintString();
func_obj_print("C++ 17 Nice!");
// member function
const Dog dog(2424);
std::function<void(const Dog&, int)> func_mem_display_num = &Dog::print_add;
func_mem_display_num(dog, 24);
return 0;
}

注意声明时可用auto进行自动类型推导,这样可以节约时间,不过这样会牺牲代码的可读性,因此需要根据情况合理使用auto

std::bind

顾名思义,std::bind函数用来绑定函数的某些参数并生成一个新的function对象。
bind用于实现偏函数(Partial Function),相当于实现了函数式编程中的 Currying(柯里化)。
比如有一函数的定义为:

1
2
3
void func_muti(int a, std::string&& b, const char* c, double d, char e) {
std::cout << a << ", " << b << ", " << c << ", " << d << ", " << e << "\n";
}

现在将此函数的一些参数绑定上值,其余部分用占位符对象(std::placeholders)表示。占位符是有序号的,代表调用此函数对象时参数在参数列表中的位置。比如:

1
2
auto f = std::bind(&func_muti, 24, std::placeholders::_1, "Haha", std::placeholders::_2, 'P');
f("Hehe", 24.24);

调用这个函数对象相当于调用以下函数:

1
2
3
void f(std::string&& b, double d) {
std::cout << "24" << ", " << b << ", " << "Haha" << ", " << d << ", " << 'P' << "\n";
}

文章目录
  1. 1. Callable type
  2. 2. std::function
  3. 3. std::bind