【问题标题】:C++ Interfacing queue or priority_queue as template parameter of a classC++ 接口队列或 priority_queue 作为类的模板参数
【发布时间】:2018-03-29 00:56:33
【问题描述】:

解释

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

可能的解决方案

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

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

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

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

【问题讨论】:

    标签: c++ queue priority-queue interfacing


    【解决方案1】:

    您可以使用 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);
            }
    };
    

    【讨论】:

    • 这就是我正在寻找的那种黑魔法。非常感谢。
    【解决方案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();
    }
    

    让重载解析来做它的事。

    【讨论】:

      【解决方案3】:

      我不知道这是否有意义,但对于 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

      【讨论】:

      • 在您的示例中,您不应该使用空容器来避免 UB :-)
      猜你喜欢
      • 2021-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-27
      • 1970-01-01
      相关资源
      最近更新 更多