functor 是重载了 operator() 的类,可像函数一样调用且带有状态;如 Adder(5)(10) 返回 15,它非函数指针也非 lambda,但支持内联优化与模板推导,适用于需携带不变数据的泛型场景。

functor 是什么:它就是一个重载了 operator() 的类
在 C++ 里,functor 不是语言关键字,也不是标准库类型,而是一种惯用法:只要一个类定义了 operator() 成员函数,它就能像函数一样被调用。比如:
struct Adder {
int offset;
Adder(int o) : offset(o) {}
int operator()(int x) const { return x + offset; }
};
Adder add5(5);
int result = add5(10); // 等价于 add5.operator()(10),返回 15
关键点在于:它不是函数指针,也不是 lambda(虽然 lambda 编译后也生成 functor),而是有状态、可定制、能内联的类实例。你传的是对象,不是地址,所以编译器更容易优化。
为什么不用普通函数或 lambda:状态和模板推导需求
当需要携带数据(如阈值、权重、缓存)且该数据在调用间保持不变时,functor 比捕获 lambda 更可控——尤其在泛型上下文中。比如 std::sort 接收比较器:
struct CaseInsensitiveCompare {
bool operator()(const std::string& a, const std::string& b) const {
return std::lexicographical_compare(
a.begin(), a.end(), b.begin(), b.end(),
[](char x, char y) { return std::tolower(x) < std::tolower(y); }
);
}
};
std::vector v = {"Zoo", "apple", "Banana"};
std::sort(v.begin(), v.end(), CaseInsensitiveCompare{});
这里不能直接用带捕获的 lambda(如 [&](...){...})传给模板函数,因为闭包类型无法显式写出;而无捕获 lambda 虽可退化为函数指针,但失去状态能力。functor 显式、可命名、可特化,适合复杂策略封装。
立即学习“C++免费学习笔记(深入)”;
和 std::function 的区别:开销与灵活性取舍
std::function 是类型擦除容器,能装任何可调用物(函数指针、lambda、functor),但带来间接调用开销(虚函数或函数指针跳转)和内存分配可能(小对象优化虽存在,但不保证)。functor 是具体类型,零成本抽象:
- 作为模板参数传入(如
std::transform(..., MyFunctor{})),编译器可见全部实现,通常内联 - 不能动态替换行为(比如运行时从 A functor 切换到 B),
std::function可以 - 成员变量可公开/私有,支持继承、特化、SFINAE 检查;
std::function只暴露调用接口
简单说:写算法库、STL 风格组件、性能敏感路径,优先用 functor;做配置驱动、插件系统、回调注册,再考虑 std::function。
容易踩的坑:const 正确性、移动语义和模板参数推导
常见错误集中在三个地方:
- 忘记
operator()加const:若 functor 被传给只接受 const 引用的算法(如std::for_each内部),非 const 版本无法匹配 - 含非 trivial 成员(如
std::vector)时,未定义移动构造/赋值:STL 算法可能复制 functor 实例,若拷贝代价大又没禁用或优化,会拖慢性能 - 模板函数中用 auto 推导 functor 类型:可能意外推成左值引用,导致后续调用失败;建议显式写类型或用
decltype(f())辅助
最隐蔽的问题是 functor 对象被算法多次复制却没意识到——比如在 std::transform 中每个元素都 new 一个内部缓存,结果创建了 N 份冗余状态。真正需要共享状态时,应通过指针或引用传递,而非依赖 functor 本身。
