如何重载含双模板参数的类方法以支持std::function作为参数?
解决方案:修复std::function注册的模板编译错误
首先指出原代码中的基础错误:
- 成员变量类型与名称完全不匹配:
m_binaryOperations被定义为std::vector<unFuncPtr>,m_unaryOperations被定义为std::vector<binFuncPtr>,会导致函数存储类型错误。 - 原模板函数中的
if是运行时判断,编译时会尝试执行两个分支的push_back,无论argsCount的值是什么,这会触发lambda无法同时转换为单参和双参std::function的编译错误。
方案1:使用C++17的if constexpr(简洁直观)
利用编译时分支判断,只生成对应argsCount的代码,避免不必要的类型转换尝试:
#include <functional> #include <vector> typedef std::function<int(int)> unFuncPtr; typedef std::function<int(int, int)> binFuncPtr; class Operations { public: template <size_t argsCount, class T> void RegisterOperator(T fn) { if constexpr (argsCount == 1) { m_unaryOperations.push_back(std::move(fn)); } else if constexpr (argsCount == 2) { m_binaryOperations.push_back(std::move(fn)); } } private: // 修正成员变量的类型与名称匹配 std::vector<unFuncPtr> m_unaryOperations; std::vector<binFuncPtr> m_binaryOperations; };
调用方式保持不变:
Operations operations; operations.RegisterOperator<1>([](int x) {return x * x; }); operations.RegisterOperator<2>([](int x, int y) {return x + y; });
方案2:使用std::enable_if(兼容C++11/14)
如果需要兼容C++17之前的版本,用std::enable_if约束模板函数,确保每个模板只匹配对应的参数数量:
#include <functional> #include <vector> #include <type_traits> typedef std::function<int(int)> unFuncPtr; typedef std::function<int(int, int)> binFuncPtr; class Operations { public: // 匹配单参可调用对象(argsCount=1) template <size_t argsCount = 1, class T, typename = std::enable_if_t<argsCount == 1 && std::is_invocable_r_v<int, T, int>>> void RegisterOperator(T fn) { m_unaryOperations.push_back(std::move(fn)); } // 匹配双参可调用对象(argsCount=2) template <size_t argsCount = 2, class T, typename = std::enable_if_t<argsCount == 2 && std::is_invocable_r_v<int, T, int, int>>> void RegisterOperator(T fn) { m_binaryOperations.push_back(std::move(fn)); } private: std::vector<unFuncPtr> m_unaryOperations; std::vector<binFuncPtr> m_binaryOperations; };
为什么之前的尝试失败?
模板特化未生效:
你写的特化版本参数是unFuncPtr/binFuncPtr,但调用时传入的是lambda(匿名类型),编译器推导的T是lambda类型而非std::function类型,因此会匹配主模板而非特化版本。部分特化成员函数非法:
C++不允许对成员函数进行部分特化(只特化非类型模板参数argsCount,保留类型模板参数T),因此第二种重载方式会触发编译错误。
内容的提问来源于stack exchange,提问作者Jr_vv
相关产品推荐
相关产品推荐

