【问题标题】:std::queue with different container type depending on runtime data根据运行时数据,具有不同容器类型的 std::queue
【发布时间】:2016-02-05 17:40:39
【问题描述】:

我有一个类需要使用 std::queue 作为实例变量来存储一些数据。我的问题是 std::queue 要么默认使用 std::deque 作为容器类型,要么需要在编译时提供另一种容器类型。但是我想使用哪个容器取决于类用户的一些运行时数据,因此我无法在编译时指定它。在实例化 std::queue 并提供正确的容器实现之后,我不再关心容器本身,而只使用 std::queue 的接口。

我想提供的容器是 std::deque 或 boost::circular_buffer 并且都存储相同类型的元素,只是当调用者想要存储无限量的数据和循环_buffer时使用一个如果没有。

到目前为止,我发现的唯一方法是自定义抽象基类充当公共接口,并为不同的 std::queue 实例提供两个派生实现。但在那种情况下,我必须复制 std::queue 的接口,这真的很烦人。

有没有办法以这种方式声明和实例化 std::queue?类似于“std::queue with unknown/runtime provided container”。

【问题讨论】:

    标签: c++ boost stl


    【解决方案1】:

    模板参数在编译类型时必须是已知的。您将无法在运行时更改 queue 的底层容器。您可以做的是某种包装器或联合,将两种类型的队列组合在一起,然后根据运行时条件在运行时使用其中一种。

    【讨论】:

      【解决方案2】:

      如果您不希望有很多该类的实例,那么一种技术含量非常低、简单但最终可行的方法是简单地将两个不同的成员变量添加到您的类中:std::queue<T> 和一个std::queue<T, boost::circular_buffer<T>>。然后在实例化类时在运行时选择适当的容器。

      这将花费您每个类实例的一些额外字节,因为每个实例中都会有一个未使用的空容器,但同时可以避免您在使用联合时可能遇到的任何困难或过于复杂的代码,@ 987654323@、void* 或类似的东西。

      这是一个完整的例子:

      #include <boost/circular_buffer.hpp>
      #include <queue>
      #include <deque>
      #include <iostream>
      
      class YourClass
      {
      public:
          YourClass(bool needs_infinite_amount_of_data) :
              needs_infinite_amount_of_data(needs_infinite_amount_of_data),
              queue(),
              queue_with_circular_buffer(boost::circular_buffer<int>(needs_infinite_amount_of_data ? 0 : 100))
          {
          }
      
          void Operation()
          {
              if (needs_infinite_amount_of_data)
              {
                  Operation(queue);
              }
              else
              {
                  Operation(queue_with_circular_buffer);
              }
          }
      
      private:
          template <class Container>
          static void Operation(Container& container)
          {
              container.push(1);
              std::cout << container.front() << "\n";
          }
      
          bool needs_infinite_amount_of_data;
          std::queue<int> queue;
          std::queue<int, boost::circular_buffer<int>> queue_with_circular_buffer;
      };
      
      int main()
      {
          YourClass obj(false);
          obj.Operation();
      }
      

      【讨论】:

      • 我自己想到了一些事情,但这是否意味着我需要一个包装器检查容器以用于我访问容器的每个方法?就像你的两个操作方法一样......我没有得到像 Container& getContainer() 使用模板工作的东西。
      • @ThorstenSchöning:是的,你需要那个包装器。但是在 any 的情况下你需要它。它可能在形式或语法上有所不同,但是每个成员函数都必须在运行时决定使用哪个容器。
      • 没错,但我更喜欢创建自己的带有重复 std::queue 接口的小抽象类,并提供它的两个具体实现,我的使用类的 CTOR 可以在它们之间进行选择。这样,我只有一个地方需要记住创建正确的 std::queue 实例,而其他方法对我的抽象类起作用。所有这些“如果...否则”是我试图避免的。
      猜你喜欢
      • 2019-04-23
      • 1970-01-01
      • 2013-06-02
      • 1970-01-01
      • 1970-01-01
      • 2014-05-30
      • 1970-01-01
      • 2021-03-23
      • 1970-01-01
      相关资源
      最近更新 更多