11.6 标准库function类型¶
可调用对象与调用形式¶
C++语言中有几种可调用的对象:函数、函数指针、lambda表达式、bind创建的对象以及重载了函数调用运算符的类。可调用的对象和其他对象一样都有类型(比如每个lambda有它自己唯一的(未命名)类类型,函数及函数指针的类型则由其返回值类型和实参类型决定),然而两个不同类型的可调用对象缺可能共享同一种调用形式call signature。
调用形式指明了调用返回的类型以及传递给调用的实参类型,一种调用形式对应一个函数类型,例如:
// 函数类型: 接受两个int并返回一个int
int(int, int);
下面三种不同的可调用对象都实现了该函数类型:
// 普通函数
int add(int i, int j) { return i + j; }
// lambda表达式
auto mod = [](int i, int j) { return i % j; };
// 重载了函数调用运算符的类
struct divide {
int operator()(int denominator, int divisor) {
return denominator / divisor;
}
};
标准库function类型¶
function定义在functional头文件中,可以将可调用对象按照调用形式进行分类。
1. 操作¶
| 操作 | 功能 |
|---|---|
function<T> f |
f是一个用来存储可调用对象的空function,这些可调用对象的调用形式应该与函数类型T相同 |
function<T> f(nullptr) |
显式地构造一个空funciton |
function<T> f(obj) |
在f中存储可调用对象obj的副本 |
f |
将f作为条件:当f含有一个可调用对象时为真;否则为假 |
f(args) |
调用f中的对象,参数是args |
2. 类型成员¶
| 类型成员 | 含义 |
|---|---|
result_type |
该function类型的可调用对象返回的类型 |
argument_typefirst_argument_typesecond_argument_type |
当T有一个或两个实参时定义的类型,如果T只有一个实参,则argument_type是该类型的同义词;如果T有两个实参,则first_argument_type和second_argument_type分别代表两个实参的类型 |
3. 例子¶
#include<iostream>
#include<functional>
// 普通函数
int add(int i, int j) { return i + j; }
// lambda表达式
auto mod = [](int i, int j) { return i % j; };
// 重载了函数调用运算符的类
struct divide {
int operator()(int denominator, int divisor) {
return denominator / divisor;
}
};
int main() {
std::function<int(int, int)> f1 = add; // 函数指针
std::function<int(int, int)> f2 = divide(); // 函数对象类的对象
std::function<int(int, int)> f3 = [](int i, int j) { return i * j; }; // lambda
std::cout << f1(4, 2) << std::endl; // 打印6
std::cout << f2(4, 2) << std::endl; // 打印2
std::cout << f3(4, 2) << std::endl; // 打印8
}
我们把所有可调用对象,包括函数指针、lambda或者函数对象都添加到map中:
// 列举了可调用对象与二元运算符对应关系的表格
// 可调用对象需要接收两个int,返回一个int
// 其中的元素可以是函数指针、函数对象或者lambda
std::map<std::string, std::function<int(int, int)>> binops = {
{"+", add}, // 函数指针
{"-", std::minus<int>()}, // 标准库函数对象
{"/", divide()}, // 用户定义的函数对象
{"*", [](int i, int j) {return i * j;} }, // 未命名的lambda
{"%", mod}}; // 命名了的mod对象
// 调用方式
binops["+"](10, 5); // 调用add(10, 5)
binops["-"](10, 5); // 调用minus<int>对象的调用运算符
binops["/"](10, 5); // 调用divide对象的调用运算符
binops["*"](10, 5); // 调用lambda对象
binops["%"](10, 5); // 调用lambda对象