如何在运行时根据条件定义C++类成员函数指针?
解决方案:运行时绑定不同参数类型的函数指针,避免重复判断
针对你需要在类构造时一次性绑定不同参数类型的候选函数,且后续调用无需条件判断的场景,提供两种可行实现方式:
方法1:使用std::function结合类型擦除
通过std::function包装不同参数的函数,配合类型擦除统一调用接口,构造时完成绑定:
#include <functional> #include <vector> // 模拟外部库定义的类型与结构体 struct StructTypeA { int a_field; }; struct StructTypeB { float b_field; }; struct Type1 { std::vector<StructTypeA> vec; }; struct Type2 { std::vector<StructTypeB> vec; }; void functionCandidate1(const int& arg1, Type1& arg2) { // 操作Type1的结构体成员(外部库定义,成员名与Type2不同) for (auto& item : arg2.vec) { item.a_field += arg1; } } void functionCandidate2(const int& arg1, Type2& arg2) { // 操作Type2的结构体成员(外部库定义,成员名与Type1不同) for (auto& item : arg2.vec) { item.b_field += static_cast<float>(arg1); } } class MyClass { private: std::function<void(const int&, void*)> class_function_; void* arg2_ptr_; // 类型擦除存储arg2指针 public: // 构造时传入选择标记与对应的arg2对象 template<typename T> MyClass(bool use_candidate_1, T& arg2) : arg2_ptr_(&arg2) { if (use_candidate_1) { class_function_ = [](const int& arg1, void* ptr) { functionCandidate1(arg1, *static_cast<Type1*>(ptr)); }; } else { class_function_ = [](const int& arg1, void* ptr) { functionCandidate2(arg1, *static_cast<Type2*>(ptr)); }; } } // 统一调用接口,无额外条件判断 void invoke(const int& arg1) { class_function_(arg1, arg2_ptr_); } };
关键点:
- 利用lambda将不同参数类型的函数适配为统一的
void(const int&, void*)签名 - 构造时完成绑定,后续调用直接执行包装后的函数,无分支判断
- 需确保传入的
arg2对象生命周期长于MyClass实例,避免悬空指针
方法2:多态基类封装(极致性能)
如果追求最小运行开销,可通过多态实现类型隔离,避免std::function的轻微性能损耗:
#include <memory> #include <vector> // 模拟外部库类型(同方法1) struct StructTypeA { int a_field; }; struct StructTypeB { float b_field; }; struct Type1 { std::vector<StructTypeA> vec; }; struct Type2 { std::vector<StructTypeB> vec; }; void functionCandidate1(const int& arg1, Type1& arg2) { /* ... */ } void functionCandidate2(const int& arg1, Type2& arg2) { /* ... */ } // 抽象基类定义统一调用接口 class FuncWrapper { public: virtual ~FuncWrapper() = default; virtual void call(const int& arg1) = 0; }; // 对应Type1的具体包装类 class WrapperForType1 : public FuncWrapper { private: Type1& target_; public: WrapperForType1(Type1& target) : target_(target) {} void call(const int& arg1) override { functionCandidate1(arg1, target_); } }; // 对应Type2的具体包装类 class WrapperForType2 : public FuncWrapper { private: Type2& target_; public: WrapperForType2(Type2& target) : target_(target) {} void call(const int& arg1) override { functionCandidate2(arg1, target_); } }; class MyClass { private: std::unique_ptr<FuncWrapper> wrapper_; public: template<typename T> MyClass(bool use_candidate_1, T& arg2) { if (use_candidate_1) { wrapper_ = std::make_unique<WrapperForType1>(static_cast<Type1&>(arg2)); } else { wrapper_ = std::make_unique<WrapperForType2>(static_cast<Type2&>(arg2)); } } void invoke(const int& arg1) { wrapper_->call(arg1); } };
关键点:
- 构造时创建对应类型的包装类实例,通过基类指针调用虚函数
- 虚函数调用开销极小,适合频繁调用的场景
- 同样需要保证
arg2对象生命周期大于MyClass实例
内容的提问来源于stack exchange,提问作者Morten Nissov
相关产品推荐
相关产品推荐

