如何实现C++类内接收同属类模板函数为参数的函数?
最优实现方案
方案1:模板成员函数指针参数(类型安全+零开销)
利用模板特性让doOp接受类内模板运算函数的指针,编译期完成类型检查,无额外运行时开销,是性能最优的实现方式。
头文件实现
#include <stdexcept> template <typename T> class FunctionPointer { public: // 模板运算函数,支持任意数值类型 T doAdd(T a, T b) { return a + b; } T doSub(T a, T b) { return a - b; } T doMul(T a, T b) { return a * b; } T doDiv(T a, T b) { if (b == 0) throw std::invalid_argument("Division by zero"); return a / b; } // 模板doOp函数,第三个参数为类内成员函数指针 template <typename Op> T doOp(T a, T b, Op op) { return (this->*op)(a, b); } };
主文件调用示例
#include "FunctionPointer.h" #include <iostream> int main() { FunctionPointer<int> fpInt; std::cout << fpInt.doOp(5, 3, &FunctionPointer<int>::doAdd) << "\n"; // 输出8 std::cout << fpInt.doOp(5, 3, &FunctionPointer<int>::doSub) << "\n"; // 输出2 FunctionPointer<double> fpDouble; std::cout << fpDouble.doOp(10.5, 2.0, &FunctionPointer<double>::doMul) << "\n"; // 输出21.0 std::cout << fpDouble.doOp(10.0, 2.0, &FunctionPointer<double>::doDiv) << "\n"; // 输出5.0 return 0; }
方案2:std::function参数(高灵活性)
如果需要支持非成员函数、Lambda表达式等扩展场景,可以用std::function作为参数,代价是微小的运行时间接调用开销。
头文件实现
#include <stdexcept> #include <functional> template <typename T> class FunctionPointer { public: T doAdd(T a, T b) { return a + b; } T doSub(T a, T b) { return a - b; } T doMul(T a, T b) { return a * b; } T doDiv(T a, T b) { if (b == 0) throw std::invalid_argument("Division by zero"); return a / b; } T doOp(T a, T b, std::function<T(T, T)> op) { return op(a, b); } };
主文件调用示例
#include "FunctionPointer.h" #include <iostream> #include <functional> int main() { FunctionPointer<int> fpInt; // 绑定类内成员函数 std::cout << fpInt.doOp(5, 3, std::bind(&FunctionPointer<int>::doAdd, &fpInt, std::placeholders::_1, std::placeholders::_2)) << "\n"; // 直接使用Lambda std::cout << fpInt.doOp(5, 3, [&](int a, int b){ return fpInt.doSub(a, b); }) << "\n"; return 0; }
兼容现有代码的解决方案
场景1:现有类已是模板类
直接在原类中添加方案1的模板doOp函数即可,原有调用doAdd/doSub等函数的代码完全不受影响,新功能可按需调用。
场景2:现有类为非模板类(仅支持特定类型)
方式A:类模板化+保留别名兼容
将原类改为模板类,同时定义原类名的别名,保证现有代码无需修改即可继续使用:
#include <stdexcept> template <typename T> class FunctionPointer { public: T doAdd(T a, T b) { return a + b; } T doSub(T a, T b) { return a - b; } T doMul(T a, T b) { return a * b; } T doDiv(T a, T b) { if (b == 0) throw std::invalid_argument("Division by zero"); return a / b; } template <typename Op> T doOp(T a, T b, Op op) { return (this->*op)(a, b); } }; // 保留原类名别名,兼容现有代码(原代码中FunctionPointer等价于FunctionPointer<int>) using FunctionPointer = FunctionPointer<int>;
方式B:新增模板成员函数不修改原有结构
在原非模板类中新增模板版本的运算函数和doOp,原有特定类型的函数保留,实现新旧代码兼容:
#include <stdexcept> class FunctionPointer { public: // 原有仅支持int的函数 int doAdd(int a, int b) { return a + b; } int doSub(int a, int b) { return a - b; } // 新增模板运算函数,支持任意类型 template <typename T> T doAdd(T a, T b) { return a + b; } template <typename T> T doSub(T a, T b) { return a - b; } template <typename T> T doMul(T a, T b) { return a * b; } template <typename T> T doDiv(T a, T b) { if (b == 0) throw std::invalid_argument("Division by zero"); return a / b; } // 模板doOp函数 template <typename T, typename Op> T doOp(T a, T b, Op op) { return (this->*op)(a, b); } };
关键注意事项
- 类内模板函数的指针必须明确指定模板参数(如
&FunctionPointer<int>::doAdd),因为模板函数需实例化后才能生成指针。 - 除法运算必须处理除零异常,避免运行时崩溃。
- 使用
std::function时需包含<functional>头文件,绑定成员函数时要传入对象指针。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

