std::mem_fn仅包装类的非静态成员函数指针,需显式传入对象实例,不绑定状态,零成本抽象,严格匹配cv与引用限定符。

std::mem_fn 能包装哪些成员函数
它只接受类的非静态成员函数指针(&Class::member_func),不支持静态成员函数、自由函数、lambda 或重载函数名。传入 std::mem_fn 的必须是明确解析后的函数地址,比如有重载时得强制转型:static_cast<void>(&A::foo)</void>。
调用时必须显式提供对象实例
std::mem_fn 返回的是可调用对象,但它本身不绑定对象,每次调用都得传入实例(或指针/引用)。这点和 std::bind 或 lambda 捕获不同——它更轻量,但更“裸”:
struct X { int f(int x) { return x * 2; } };
auto fn = std::mem_fn(&X::f);
X x;
int r = fn(x, 10); // ✅ 对象按值/引用传入
int s = fn(&x, 10); // ✅ 也可传指针
常见错误是漏传对象参数,导致编译失败,报错类似 no match for call to ... (int)——因为只给了参数,没给调用目标。
和 std::bind(&X::f, obj)、[&obj](int x){return obj.f(x);} 的区别
三者都能实现“调用成员函数”,但语义和开销不同:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
std::mem_fn是零成本抽象:仅存储函数指针,无状态,无拷贝/移动构造开销;适合高频、泛型场景(如算法中传入) -
std::bind会复制或引用捕获的对象,产生额外存储和调用跳转;C++17 后已不推荐用于简单绑定 - lambda 最灵活,能捕获任意上下文,但可能隐式捕获导致生命周期风险;且每次定义类型都不同,无法作为模板参数统一处理
如果你只是想在 std::transform 或 std::for_each 中调用某个成员函数,std::mem_fn 往往是最直接、最高效的选择。
注意 const/volatile 限定符和引用限定符
成员函数的 cv 限定符必须严格匹配。比如 void foo() const 只能用 &X::foo 传给 std::mem_fn,若误传非 const 版本的地址,编译失败。
带引用限定符的函数(如 void bar() &&)也能包装,但调用时传入的对象必须是右值(或显式 std::move),否则编译不过。这点容易被忽略,尤其在容器遍历时默认拿到左值引用。
成员函数指针的类型敏感性比看起来更强,稍有不匹配就会触发模板推导失败,错误信息往往很长——建议先确认函数签名是否完全一致,再调试调用方式。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










