C++自省技术问询:判断static成员函数及相关实现需求
C++中static成员函数的自省type trait实现方案
核心限制说明
static成员函数的指针类型与同签名的自由函数指针完全一致,因此仅通过函数指针类型本身无法完成以下操作:
- 区分它是static成员函数还是自由函数
- 从指针类型反推所属类
但结合类的上下文或利用SFINAE特性,我们可以实现你的需求,以下分C14、C17、C++20版本给出具体方案。
需求1:判断某成员函数是否为static
由于函数指针类型本身无区分度,必须结合类的信息才能判断,以下方案需同时传入类类型和函数指针:
C++14实现
#include <type_traits> template <typename T, typename F> struct is_static_member : std::false_type {}; // 特化匹配函数指针类型 template <typename T, typename Ret, typename... Args> struct is_static_member<T, Ret(*)(Args...)> { private: // 尝试匹配T的static成员函数foo(可替换为目标函数名) template <typename U> static std::true_type test(decltype(&U::foo)*); template <typename U> static std::false_type test(...); public: static constexpr bool value = decltype(test<T>(nullptr))::value; }; // 变量模板简化使用 template <typename T, typename F> constexpr bool is_static_member_v = is_static_member<T, F>::value;
使用示例:
struct S { static int foo(int); }; int bar(int); // 判断S::foo是否是S的static成员 static_assert(is_static_member_v<S, decltype(&S::foo)> == true, ""); // 自由函数bar不属于S,返回false static_assert(is_static_member_v<S, decltype(&bar)> == false, "");
C++17及以后实现
利用constexpr if简化逻辑,支持更灵活的函数名适配:
template <typename T, auto F> constexpr bool is_static_member_v = []{ if constexpr (requires { &T::foo; }) { return std::is_same_v<decltype(&T::foo), decltype(F)>; } else { return false; } }();
需求2:从static成员函数指针获取所属类
仅靠函数指针类型无法反推类,但可以在传递指针时显式绑定类类型:
C++14实现
// 模板函数接收类类型和函数指针,直接返回类类型 template <typename T, typename Ret, typename... Args> T get_static_member_class(Ret(*)(Args...)) { static_assert(is_static_member_v<T, Ret(*)(Args...)>, "Function is not a static member of T"); return T{}; } // 对应你的Process函数 template <typename T, typename Ret, typename... Args> void Process(Ret(*func)(Args...)) { static_assert(is_static_member_v<T, decltype(func)>, "Invalid static member function"); // 模拟类型打印,实际可使用编译器内置宏或第三方库实现精准输出 std::cout << "struct " << typeid(T).name() << '\n'; }
调用示例:
Process<S>(S::foo); // 输出:struct S
C++20实现
结合概念(concepts)做编译期校验:
template <typename T, auto F> concept StaticMemberOf = is_static_member_v<T, decltype(F)>; template <StaticMemberOf<T> auto F, typename T> void Process() { std::cout << "struct " << typeid(T).name() << '\n'; } // 调用 Process<&S::foo, S>();
需求3:判断某个类是否拥有指定的static成员函数
此需求可通过SFINAE实现,无需依赖实验性特性:
C++14实现
#include <type_traits> // 判断类T是否有static成员函数foo,签名为Ret(Args...) template <typename T, typename Ret, typename... Args> struct has_static_foo { private: template <typename U> static std::true_type test(decltype(static_cast<Ret(*)(Args...)>(&U::foo))); template <typename U> static std::false_type test(...); public: static constexpr bool value = decltype(test<T>(nullptr))::value; }; // 变量模板简化使用(对应S::foo的签名int(int)) template <typename T> constexpr bool has_static_foo_v = has_static_foo<T, int, int>::value;
使用示例:
struct S { static int foo(int); }; struct NoFoo {}; static_assert(has_static_foo_v<S> == true, ""); static_assert(has_static_foo_v<NoFoo> == false, "");
C++17实现
利用constexpr if和requires表达式简化:
template <typename T> constexpr bool has_static_foo_v = []{ if constexpr (requires { &T::foo; }) { return std::is_same_v<decltype(&T::foo), int(*)(int)>; } else { return false; } }();
C++20实现
使用概念做更直观的约束:
template <typename T> concept HasStaticFoo = requires { { &T::foo } -> std::same_as<int(*)(int)>; }; // 使用 static_assert(HasStaticFoo<S> == true, ""); static_assert(!HasStaticFoo<NoFoo>, "");
完整整合示例(C++14版本)
#include <iostream> #include <type_traits> #include <typeinfo> // 判断类是否有指定static成员函数 template <typename T, typename Ret, typename... Args> struct has_static_foo { private: template <typename U> static std::true_type test(decltype(static_cast<Ret(*)(Args...)>(&U::foo))); template <typename U> static std::false_type test(...); public: static constexpr bool value = decltype(test<T>(nullptr))::value; }; template <typename T> constexpr bool has_static_foo_v = has_static_foo<T, int, int>::value; // 判断是否为类的static成员函数 template <typename T, typename F> struct is_static_member : std::false_type {}; template <typename T, typename Ret, typename... Args> struct is_static_member<T, Ret(*)(Args...)> { private: template <typename U> static std::true_type test(decltype(&U::foo)*); template <typename U> static std::false_type test(...); public: static constexpr bool value = decltype(test<T>(nullptr))::value; }; template <typename T, typename F> constexpr bool is_static_member_v = is_static_member<T, F>::value; // 从static成员函数获取所属类并打印 template <typename T, typename Ret, typename... Args> void Process(Ret(*func)(Args...)) { static_assert(is_static_member_v<T, decltype(func)>, "Not a static member of T"); std::cout << "struct " << typeid(T).name() << '\n'; } struct S { static int foo(int) { return 0; } }; int main() { // 判断输入是否为static成员函数 std::cout << std::boolalpha << is_static_member_v<S, decltype(&S::foo)> << '\n'; // 判断类是否拥有指定static成员函数 std::cout << std::boolalpha << has_static_foo_v<S> << '\n'; // 从成员函数获取所属类 Process<S>(&S::foo); }
输出:
true true struct S
内容的提问来源于stack exchange,提问作者Oersted
相关产品推荐
相关产品推荐

