If I want to make class TopNStorage parametrizable with comparison predicate, I have to do something like:
#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());
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";
}
}
Although, this is totally fine, the int type in std::less<int> seems to be redundant in such cases and I’d like to tell the compiler to take it from typename T of the class, but I don’t know if I can parametrize the template with another template.
Is there a way to make client code look like:
TopNStorage<int,std::less> storage(3);
Motivation
I don’t like duplication and want to avoid situations when one type could be changes without changing the other (when it comes to more complicated types and code).
Background
Based on the question Keeping top N values.
>Solution :
std::less defaults to and is specialized for void and that specialization has a comparison operator in the form of
template< class T, class U >
constexpr auto operator()( T&& lhs, U&& rhs ) const
-> decltype(std::forward<T>(lhs) < std::forward<U>(rhs));
allowing it to compare any two types as long as there is an underlying operator < for them.
You can use this specialization instead of specifying the type like
TopNStorage<int,std::less<>> storage(3);
which you can see working in this live example.