std::is_member_pointer仅对成员函数指针(如ReturnType (ClassType::)())和成员对象指针(如Type ClassType::)返回true,其余类型均返回false。

std::is_member_pointer 能识别哪些类型
std::is_member_pointer 是一个类型特征(type trait),用于判断某类型是否为「成员指针」——即指向类的非静态成员函数或非静态数据成员的指针。它只对以下两种形式返回 true:
-
ReturnType (ClassType::*)()(成员函数指针) -
Type ClassType::*(成员对象指针)
注意:普通函数指针(如 void(*)())、普通对象指针(如 int*)、nullptr_t、引用、数组、枚举等,全部返回 false。它不关心是否可访问、是否合法(比如私有成员),只做语法层面的类型分类。
如何在编译期做分支判断
结合 std::enable_if_t 或 if constexpr(c++17 起),可在模板中根据是否为成员指针启用不同逻辑。常见于泛型回调包装、反射辅助、序列化元信息提取等场景。
例如,下面这个函数模板仅接受成员指针,并提取其所属类类型:
立即学习“C++免费学习笔记(深入)”;
template auto get_class_of_member_ptr(T ptr) -> std::enable_if_t, typename std::remove_pointer_t::class_type> { // 实际无法直接取 class_type —— 这里仅为示意结构 // 真实中需借助额外 trait(如自定义 extract_class_t)或宏辅助 }
更实用的做法是配合 SFINAE 或概念(C++20)做约束:
template requires std::is_member_pointer_v void handle_member_ptr(T) { // 只有成员指针才能进这里 }
常见误判和陷阱
容易混淆的几类情况必须注意:
-
int A::*✅ 是成员指针;但int* A::*❌ 是「指向指针的成员」,仍是成员指针(std::is_member_pointer_v为true) -
decltype(&A::func)✅ 正确获得成员函数指针类型;但&A::func本身是表达式,不能直接传给std::is_member_pointer,必须用decltype -
std::is_member_pointer✅ C++17 起支持带 cv/ref-qualifier 的成员函数指针::value - 空模板参数、未实例化的类模板名(如
A)不能作为std::is_member_pointer的模板实参,会编译失败
完整可运行实例(C++17)
以下代码演示如何用 std::is_member_pointer_v 在编译期区分并处理不同类型:
#include #include struct S { int x = 42; void f() {} };
int main() { static_assert(std::is_member_pointer_v>); // true static_assert(std::is_member_pointer_v)()>); // true static_assert(!std::is_member_pointer_v>); // false static_assert(!std::is_member_pointer_v)()>); // false
if constexpr (std::is_member_pointer_vzuojiankuohaophpcndecltype(&S::x)youjiankuohaophpcn) { std::cout zuojiankuohaophpcnzuojiankuohaophpcn "S::x is a data member pointern"; } if constexpr (std::is_member_pointer_vzuojiankuohaophpcndecltype(&S::f)youjiankuohaophpcn) { std::cout zuojiankuohaophpcnzuojiankuohaophpcn "S::f is a member function pointern"; }
}
真正难的不是判断,而是后续怎么从成员指针反推类名或函数签名——std::is_member_pointer 本身不提供这些信息,需要组合 std::remove_pointer、std::is_member_function_pointer、甚至模板偏特化来进一步解构。