You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 05:35:04