基于基类重载函数推导sumClass模板参数T(C++20)
问题描述
现有如下C++代码:
class intClass { public: virtual ~intClass() = default; virtual int sum(int a, int b) const = 0; }; class doubleClass { public: virtual ~doubleClass() = default; virtual double sum(double a, double b) const = 0; }; template<typename T, typename C> class sumClass : public C { public: T sum(T a, T b) const override { return a + b; } }; int main() { sumClass<int, intClass> intSum; sumClass<double, doubleClass> doubleSum; return 0; }
已知intClass和doubleClass不可修改,需要移除sumClass的模板参数T,能否基于基类中sum函数的签名自动推导T?允许使用C++20标准,最终期望的main函数如下:
int main() { sumClass<intClass> intSum; sumClass<doubleClass> doubleSum; return 0; }
解决方案
可以实现,核心思路是用类型萃取从基类的sum函数签名里提取出目标类型T,再重构sumClass模板。
1. 实现类型萃取工具
我们需要一个工具来从基类的sum成员函数指针中提取出类型T:
#include <type_traits> // 基础模板,用于匹配成员函数指针 template<typename FuncPtr> struct extract_sum_type_from_func_ptr; // 特化模板,匹配签名为 T (C::*)(T, T) const 的成员函数 template<typename C, typename T> struct extract_sum_type_from_func_ptr<T (C::*)(T, T) const> { using type = T; }; // 封装成易用的类型别名 template<typename C> using sum_type = typename extract_sum_type_from_func_ptr<decltype(&C::sum)>::type;
这段代码的作用是:通过decltype(&C::sum)获取基类sum函数的指针类型,再通过模板特化直接提取出其中的T类型(也就是返回值和参数的类型)。
2. 重构sumClass模板
现在把sumClass改成只接受基类C作为模板参数,内部用sum_type<C>替代原来的T:
template<typename C> class sumClass : public C { public: using T = sum_type<C>; T sum(T a, T b) const override { return a + b; } };
完整可运行代码
#include <type_traits> class intClass { public: virtual ~intClass() = default; virtual int sum(int a, int b) const = 0; }; class doubleClass { public: virtual ~doubleClass() = default; virtual double sum(double a, double b) const = 0; }; // 类型萃取工具 template<typename FuncPtr> struct extract_sum_type_from_func_ptr; template<typename C, typename T> struct extract_sum_type_from_func_ptr<T (C::*)(T, T) const> { using type = T; }; template<typename C> using sum_type = typename extract_sum_type_from_func_ptr<decltype(&C::sum)>::type; // 重构后的sumClass template<typename C> class sumClass : public C { public: using T = sum_type<C>; T sum(T a, T b) const override { return a + b; } }; int main() { sumClass<intClass> intSum; sumClass<doubleClass> doubleSum; // 测试调用,验证功能正常 int result1 = intSum.sum(3, 5); // 结果为8 double result2 = doubleSum.sum(2.3, 4.7); // 结果为7.0 return 0; }
额外优化(C++20特性)
如果想要在编译期就确保传入的基类符合要求,可以用C++20的concept做约束:
template<typename C> concept HasValidSumFunc = requires(const C& obj, sum_type<C> a, sum_type<C> b) { { obj.sum(a, b) } -> std::same_as<sum_type<C>>; }; // 只有符合约束的基类才能被传入sumClass template<HasValidSumFunc C> class sumClass : public C { public: using T = sum_type<C>; T sum(T a, T b) const override { return a + b; } };
这样如果传入的基类没有符合要求的sum函数,编译器会直接报错,提前发现问题。
内容的提问来源于stack exchange,提问作者user24681855
相关产品推荐
相关产品推荐

