编译时选择调用模板类A的T成员函数foo或bar的方案问询
编译时指定调用成员函数的几种方案
既然要在编译时确定调用foo还是bar,完全可以借助C++的模板元编程特性,避免运行时间接调用的开销,以下是几种实用可行的方案:
方案1:枚举+if constexpr编译时分支
给模板类A新增一个枚举类型的模板参数标记目标成员函数,再用if constexpr做编译时判断——未选中的分支会被编译器完全剔除,不会生成多余代码:
enum class CallType { Foo, Bar }; template<class T, CallType Type> class A { public: void f() { if constexpr (Type == CallType::Foo) { t_.foo(); } else if constexpr (Type == CallType::Bar) { t_.bar(); } } private: T t_; }; // 使用示例 struct MyType { void foo() {} void bar() {} }; int main() { A<MyType, CallType::Foo> a_foo; // 编译后仅保留foo调用逻辑 a_foo.f(); A<MyType, CallType::Bar> a_bar; // 编译后仅保留bar调用逻辑 a_bar.f(); }
这种方式直观简单,C++17及以上版本支持,代码可读性高。
方案2:策略类模板参数
把调用逻辑封装成独立的策略类,作为A的模板参数传入,扩展性极强——后续要支持其他成员函数时,只需新增对应策略类即可:
// 调用foo的策略 struct CallFoo { template<class T> void operator()(T& t) const { t.foo(); } }; // 调用bar的策略 struct CallBar { template<class T> void operator()(T& t) const { t.bar(); } }; template<class T, class CallStrategy> class A { public: void f() { CallStrategy{}(t_); } private: T t_; }; // 使用示例 struct MyType { void foo() {} void bar() {} }; int main() { A<MyType, CallFoo> a_foo; a_foo.f(); A<MyType, CallBar> a_bar; a_bar.f(); }
这种方式遵循策略模式,代码解耦性好,还能给策略类添加额外逻辑(比如调用前后的预处理),灵活性拉满。
方案3:成员函数指针作为非类型模板参数
直接把T的成员函数指针作为模板参数传入,是最直接的编译时绑定方式,没有任何运行时开销:
template<class T, void (T::*MemberFunc)()> class A { public: void f() { (t_.*MemberFunc)(); } private: T t_; }; // 使用示例 struct MyType { void foo() {} void bar() {} }; int main() { A<MyType, &MyType::foo> a_foo; a_foo.f(); A<MyType, &MyType::bar> a_bar; a_bar.f(); }
这种方式代码简洁高效,但缺点是如果T的成员函数签名变化(比如新增参数),需要同步修改模板参数的签名。
内容的提问来源于stack exchange,提问作者Pablo Arias
相关产品推荐
相关产品推荐

