4

说明

我有一个类(Banana在示例中命名),它将作为模板参数(Q在示例中命名)接收 astd::queue或 a std::priority_queue。此参数所需的唯一方法是push(),pop()front()。现在的问题是:两个队列都有push()and pop(),但是(等效的)中的front()方法被命名为。我如何接口这个参数?std::priority_queuetop()Q

可能的解决方案

我正在考虑不同的解决方案,但这些都不能说服我。我正在编写一个 C++ 库,我不想要会使库用户的生活复杂化的肮脏解决方案。这是我的想法:

  • std::priority_queue创建该实现front()方法的子类。那很脏。
  • 添加另一个接受如下函数的模板参数:

    [] (const std::priority_queue& q) { q.top(); }
    

    或者

    [] (const std::queue& q) { q.front(); }
    

    取决于使用的队列类型。肮脏:使图书馆用户的生活复杂化。

  • ...

你有一个简单而优雅的吗?

这个例子

#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;
}

显然这不会编译。但我发布编译器响应以更好地解释问题:

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();

这只是一个简化的例子。真正的问题要复杂得多。

4

3 回答 3

4

您可能会使用 SFINAE 方式,例如:

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);
        }
};
于 2017-10-17T10:54:51.393 回答
2

添加一个间接级别:

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

并让重载决议做它的事。

于 2017-10-17T10:54:14.237 回答
1

我不知道这是否有意义,但使用 C++17 你可以使用std::experimental::is_detected如下:

#include <iostream>
#include <queue>
#include <set>
#include <experimental/type_traits>

template<typename T>
using front_t = decltype( std::declval<T&>().front() );

template<typename T>
constexpr bool has_front = std::experimental::is_detected_v<front_t, T >;

template<class T>
void elementTop(T& obj)
{
    if constexpr (has_front<T>)
    {
         obj.front();
         std::cout << "Front \n";
    }
    else
    {
         obj.top();
         std::cout << "Top \n";
    }
}

int main()
{

    std::priority_queue<int> q1;
    std::queue<int> q2;
    std::vector<int> vec;

    std::set<int> s;

    elementTop(q1) ;
    elementTop(q2) ;
    elementTop(vec) ;

    /* elementTop(s) ; errors out */
    return 0;
}

See Here

于 2017-10-17T11:40:02.853 回答