可调用对象
可调用对象,是可以被调用的实体。
通俗来说:x(...)
满足以下条件之一即可
- 普通函数 / 静态成员函数
- 函数指针 (
Ret(*)(Args...)) - 成员函数指针 (
Ret (C::*)(Args...),调用方式特殊) - lambda 表达式对象(本质是编译器生成的类对象)
- 函数对象 / 仿函数(functor) :定义了
operator()的类/对象 std::function:类型擦除后的可调用包装器std::bind结果(C++11 起,可调用)
std::function
头文件:#include <functional>
std::function 本质上是一个类型擦除的包装器,统一存放和管理各种类型的可调用对象。
函数签名
cpp
template< class >
class function; /* undefined */
template< class R, class... Args >
class function<R(Args...)>;
要求里面的 callable 能以 Args... 调用,并且返回值能转成 R。
基本用法
cpp
// 普通函数 || 函数指针
int add(int a, int b) {return a + b;}
function<int(int, int)> f = add;
int x = f(1, 2);
// lambda
function<int(int)> f = [](int x){ return ++x; };
int x = f(5);
// 仿函数
struct Mul {
int operator()(int a, int b) const { return a * b; }
};
function<int(int,int)> h = Mul{};
int z = h(2, 3); // 6
进阶用法
类型擦除带来的统一接口。
这里使用 function 可以放入相同函数类型的不同类型
回调列表
cpp
int add(int a, int b) {return a + b;}
struct Mul {
int operator()(int a, int b) const { return a * b; }
};
vector<function<int(int,int)>> v;
v.push_back(add);
v.push_back(Mul{});
for (auto e : v) {
e(10, 3);
}
回调参数
cpp
void run(std::function<int(int)> op) {
int r = op(10);
}
run([](int x){
return x * x;
});
注意事项
空状态
std::function 可以是"空的":
如果对空的 std::function 直接调用,会抛:
std::bad_function_call
cpp
std::function<void()> f;
if (!f) { /* 空 */ }
try {
f();
} catch (const std::bad_function_call&) {
// ...
}