c++queuepriority-queueinterfacing

C++ Interfacing queue or priority_queue as template parameter of a class


The explanation

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?

Possible solutions

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:

Do you have one that's simple and elegant?

The example

#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.


Solution

  • 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);
            }
    };