如何避免传递重复依赖类型?优化TopNStorage模板参数写法
实现TopNStorage类的谓词模板参数自动推导,避免类型冗余
当前实现的TopNStorage类模板需要手动指定谓词的具体实例化类型(如std::less<int>),其中int与类模板的T类型重复,希望优化为仅传入谓词模板(如std::less),让编译器自动从T推导谓词的类型参数,使客户端代码可以写成:
TopNStorage<int, std::less> storage(3);
原实现代码
#include <algorithm> #include <iostream> #include <queue> #include <vector> template <typename T, typename Pred = std::greater<T>> class TopNStorage { std::priority_queue<T, std::vector<T>, Pred> counts; size_t n; public: TopNStorage(size_t n) : n(n) { } void add(T value) { if (counts.size() >= n) { if (Pred()(value, counts.top())) { counts.pop(); counts.push(value); } } else { counts.push(value); } } auto get_values() const { std::vector<T> sorted_collocations_counts(counts.size()); std::copy(&(counts.top()), &(counts.top()) + counts.size(), sorted_collocations_counts.begin()); std::sort(sorted_collocations_counts.begin(), sorted_collocations_counts.end(),Compare()); return sorted_collocations_counts; } }; int main() { TopNStorage<int,std::less<int>> storage(3); for (int i = 1; i <= 5; ++i) { storage.add(i); } for (auto value : storage.get_values()) { std::cout << value << "\n"; } }
解决方案:使用模板模板参数
通过将类模板的第二个参数改为模板模板参数,可以实现谓词类型的自动推导,避免重复指定T类型。
修改后的完整代码
#include <algorithm> #include <iostream> #include <queue> #include <vector> #include <functional> // 用于std::not_fn // 将第二个参数改为模板模板参数,默认使用std::greater template <typename T, template <typename> typename Pred = std::greater> class TopNStorage { // 用T实例化Pred模板,得到具体的谓词类型 using PredType = Pred<T>; std::priority_queue<T, std::vector<T>, PredType> counts; size_t n; public: TopNStorage(size_t n) : n(n) { } void add(T value) { if (counts.size() >= n) { // 实例化PredType对象进行比较 if (PredType()(value, counts.top())) { counts.pop(); counts.push(value); } } else { counts.push(value); } } auto get_values() const { std::vector<T> result(counts.size()); // 修复拷贝逻辑:priority_queue的底层元素不按堆序连续排列,需通过临时队列遍历 auto temp_queue = counts; size_t idx = 0; while (!temp_queue.empty()) { result[idx++] = temp_queue.top(); temp_queue.pop(); } // 反转谓词排序,让输出结果符合直观的顺序 std::sort(result.begin(), result.end(), std::not_fn(PredType())); return result; } }; int main() { // 仅传入std::less模板,无需指定<int> TopNStorage<int, std::less> storage(3); for (int i = 1; i <= 5; ++i) { storage.add(i); } for (auto value : storage.get_values()) { std::cout << value << "\n"; } }
关键修改点说明
- 模板参数调整:将原有的
typename Pred改为template <typename> typename Pred,允许传入一个模板(如std::less、std::greater)而非实例化后的类型。 - 谓词自动实例化:在类内部通过
using PredType = Pred<T>,用类模板的T自动推导并实例化谓词模板,彻底消除类型冗余。 - 修复拷贝逻辑:原代码直接通过
&counts.top()拷贝的方式错误,因为std::priority_queue的底层容器元素并非按堆序排列,改为通过临时队列遍历拷贝,保证元素完整取出。 - 排序逻辑优化:使用
std::not_fn反转谓词,让输出结果的排序符合直观预期(例如用std::less时,队列存最大的N个元素,反转后输出升序结果)。
效果验证
修改后的客户端代码只需写TopNStorage<int, std::less>,无需重复指定int,既减少了代码冗余,也避免了因类型不同步导致的错误。
内容的提问来源于stack exchange,提问作者Damir Tenishev
相关产品推荐
相关产品推荐

