如何实现指向不同返回类型类Getter的多用途成员函数指针?
实现指向任意返回类型Getter的通用"指针"
嘿,这个需求我懂——想搞一个能指向不同返回类型Getter的通用“指针”是吧?普通的C++成员函数指针因为强类型绑定(比如int (MyClass::*)()和std::string (MyClass::*)()是完全不同的类型),肯定没法直接用同一个变量存储。咱们得靠类型擦除或者变体类型来绕开这个限制,下面给你两种实用的实现思路:
方案1:用std::variant存储已知类型的Getter指针
如果你已经明确知道所有Getter的返回类型(比如int和string),用std::variant是最高效的选择——它不需要动态分配内存,直接把不同类型的成员函数指针存在一个可判别类型的容器里。
完整代码示例
#include <variant> #include <string> #include <stdexcept> class MyClass { private: int i = 42; std::string str = "hello"; public: int getI() { return i; } std::string getStr() { return str; } }; // 定义变体类型,包含所有可能的Getter成员函数指针 using GetterVariant = std::variant<int (MyClass::*)(), std::string (MyClass::*)()>; // 辅助调用函数:根据目标返回类型提取并调用对应的Getter template<typename ResultType> ResultType call_getter(MyClass& obj, GetterVariant& getter_var) { auto getter_ptr = std::get_if<ResultType (MyClass::*)()>(&getter_var); if (!getter_ptr) { throw std::bad_variant_access(); } return (obj.**getter_ptr)(); } int main() { MyClass obj; GetterVariant pointerToAnyMethod; // 指向getI()方法 pointerToAnyMethod = &MyClass::getI; int gotI = call_getter<int>(obj, pointerToAnyMethod); // gotI = 42 // 切换指向getStr()方法 pointerToAnyMethod = &MyClass::getStr; std::string gotStr = call_getter<std::string>(obj, pointerToAnyMethod); // gotStr = "hello" }
思路解释
GetterVariant把所有合法的Getter类型打包成一个变体,编译器会跟踪当前存储的是哪种类型。call_getter模板函数需要你明确指定返回类型,它会尝试从变体中提取对应类型的成员函数指针,成功就调用,失败则抛出异常。
方案2:用类型擦除包装类支持任意返回类型
如果未来可能新增其他返回类型的Getter,不想每次都修改变体定义,可以用类型擦除的包装类,配合std::any来存储返回值,实现完全通用的Getter指针。
完整代码示例
#include <functional> #include <string> #include <memory> #include <any> #include <stdexcept> class MyClass { private: int i = 42; std::string str = "hello"; public: int getI() { return i; } std::string getStr() { return str; } }; class AnyGetter { private: // 抽象基类:定义统一的调用接口 class GetterConcept { public: virtual ~GetterConcept() = default; virtual std::any call(MyClass& obj) const = 0; }; // 模板实现类:包装具体类型的Getter template<typename ResultType> class GetterModel : public GetterConcept { private: ResultType (MyClass::*getter_func)(); public: GetterModel(ResultType (MyClass::*func)()) : getter_func(func) {} std::any call(MyClass& obj) const override { return (obj.*getter_func)(); } }; std::unique_ptr<GetterConcept> impl; public: // 构造函数:接受任意类型的Getter成员函数指针 template<typename ResultType> AnyGetter(ResultType (MyClass::*func)()) : impl(std::make_unique<GetterModel<ResultType>>(func)) {} // 重载调用运算符:返回std::any类型的结果 std::any operator()(MyClass& obj) const { if (!impl) { throw std::runtime_error("Getter not initialized"); } return impl->call(obj); } }; int main() { MyClass obj; // 指向getI() AnyGetter pointerToAnyMethod(&MyClass::getI); int gotI = std::any_cast<int>(pointerToAnyMethod(obj)); // 42 // 切换指向getStr() pointerToAnyMethod = AnyGetter(&MyClass::getStr); std::string gotStr = std::any_cast<std::string>(pointerToAnyMethod(obj)); // "hello" }
思路解释
- 用
GetterConcept抽象基类隐藏具体Getter的类型,GetterModel模板类负责包装不同类型的成员函数指针。 - 调用时返回
std::any类型,你需要用std::any_cast把它转换成目标类型(转换错误会抛出异常)。
关键注意点
C++是强类型语言,没法做到完全“无类型”的通用指针——你要么提前知道所有可能的返回类型(方案1),要么在调用时明确指定要转换的类型(方案2)。两种方案都能满足你的需求,选哪个取决于你是否需要扩展新的Getter类型。
内容的提问来源于stack exchange,提问作者Yaroslav Hladkyi
相关产品推荐
相关产品推荐

