I have a class (named Banana
in the example) that would receive as a template argument (named Q
in the example) a std::queue
or a std::priority_queue
. The only methods that are required for this argument are push()
, pop()
and front()
. Now the problem: both queues have push()
and pop()
, but the front()
method in the std::priority_queue
(the equivalent one) is named top()
. How can I interface this parameter Q
?
I'm thinking about different solutions, but none of these convinces me. I'm writing a C++ library and I don't want dirty solutions that would complicate the life of the library user. Here is what I've thought:
std::priority_queue
that implements front()
method. That's dirty.Add another template argument that accepts a function like:
[] (const std::priority_queue& q) { q.top(); }
or
[] (const std::queue& q) { q.front(); }
depending on the used queue type. Dirty: complicates life to the library user.
Do you have one that's simple and elegant?
#include <iostream>
#include <queue>
#include <utility>
template <typename T, class Q = std::queue<T>>
class Banana
{
private:
Q queue;
public:
void push(T&& o)
{
queue.push(std::move(o));
}
const T& top()
{
return queue.front();
}
};
int main()
{
Banana<int> banana0;
banana0.push(0);
std::cout << banana0.top() << std::endl;
Banana<int, std::priority_queue<int>> banana1;
banana1.push(1);
std::cout << banana1.top() << std::endl;
return 0;
}
Obviously this won't compile. But I'm posting the compiler response to explain better the problem:
test.cxx: In instantiation of ‘const T& Banana<T, Q>::top() [with T = int; Q = std::priority_queue<int>]’:
test.cxx:32:34: required from here
test.cxx:20:30: error: ‘class std::priority_queue<int>’ has no member named ‘front’
return queue.front();
This is only a simplified example. The real problem is much more complex.
You might use the SFINAE way, something like:
template <typename T, class Q = std::queue<T>>
class Banana
{
private:
Q queue;
template <typename Queue>
static
auto private_top(Queue& queue) -> decltype(queue.top()) { return queue.top();}
template <typename Queue>
static
auto private_top(Queue& queue) -> decltype(queue.front()) { return queue.front();}
public:
void push(T&& o)
{
queue.push(std::move(o));
}
const T& top()
{
return private_top(queue);
}
};
Add a level of indirection:
template<typename T, class C>
auto& front_or_top(std::queue<T, C> const &q) {
return q.front();
}
template<typename T, class C, typename Comp>
auto& front_or_top(std::priority_queue<T, C, Comp> const &q) {
return q.top();
}
And let overload resolution do its thing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With