如何从成员指针模板类型获取类类型以实现通用排序模板
解决
order_by模板依赖具体类型的问题 要让你的order_by模板完全独立于具体类类型,核心是从成员指针类型中自动推导类类型和成员类型,不需要硬编码Person这类具体类型。下面是具体的改造方案:
1. 改造order_by模板
我们可以利用C++的模板参数推导,直接从成员指针Member Class::*中解析出所属的类Class和成员类型Member,让模板完全通用:
#include <functional> #include <vector> #include <algorithm> #include <string> struct Person { std::string name; int age, height; }; // 通用的order_by模板:自动推导类类型和成员类型 template <typename Class, typename Member> auto order_by(Member Class::*member_ptr) { return [member_ptr](const Class& a, const Class& b) { return a.*member_ptr < b.*member_ptr; }; }
这个模板的原理是:当你传入&Person::age时,编译器会自动匹配Class=Person、Member=int,生成针对Person类型的lambda,完全不需要显式指定类类型。
2. 保留并适配链式比较的operator|
你之前写的operator|模板已经是通用的了(因为用了auto参数),可以直接和改造后的order_by配合使用,仅做一点小优化让参数更严谨:
// 通用的链式比较组合模板 template<class F1, class F2> auto operator|(F1 f1, F2 f2) { return [f1, f2](const auto& a, const auto& b) { const bool res = f1(a, b); const bool inv_res = f1(b, a); // 如果两次比较结果不同,说明a和b有大小关系,返回第一次结果;否则用第二个规则 if (res != inv_res) return res; return f2(a, b); }; }
这里把参数改成const auto&可以避免不必要的拷贝,同时保持对任意类型的兼容性。
3. 测试示例用法
现在你可以像之前一样正常使用,而且order_by可以支持任何自定义类型:
int main() { std::vector<Person> persons = { {"Alice", 25, 165}, {"Bob", 30, 180}, {"Charlie", 25, 170} }; // 按age找最大元素 auto result = std::max_element(persons.begin(), persons.end(), order_by(&Person::age)); // 输出Bob(年龄30最大) // 先按age排序,age相等时按height找最大 result = std::max_element(persons.begin(), persons.end(), order_by(&Person::age) | order_by(&Person::height)); // 输出Charlie(年龄25,身高170比Alice高) return 0; }
额外优化(可选)
如果想要支持更多比较逻辑(比如降序、大于比较),可以扩展模板,增加一个比较器参数,默认用std::less<>:
template <typename Class, typename Member, typename Comparator = std::less<>> auto order_by(Member Class::*member_ptr, Comparator comp = {}) { return [member_ptr, comp](const Class& a, const Class& b) { return comp(a.*member_ptr, b.*member_ptr); }; } // 用法示例:按age降序 auto desc_age = order_by(&Person::age, std::greater<>());
这样你的模板会更加灵活,能适配更多排序场景。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

