【问题标题】:C++ vector with wrapping random access?带有包装随机访问的C++向量?
【发布时间】:2016-07-12 15:41:40
【问题描述】:

我真正想要的是 C++ 中的容器类,它在各方面都与 STL 向量类完全相同,只是 [] 运算符具有包装行为。例如:

vector<int>  myVec;
myVec.push_back(5);
myVec.push_back(10);
myVec.push_back(15);

cout << myVec[ 5] << endl;   // would output 15
cout << myVec[ 1] << endl;   // would output 10
cout << myVec[-2] << endl;   // would output 10

这样的容器是否已经存在,或者是否可以重载或重新定义向量模板中的 [] 运算符?

我见过Boost circular buffer,它的行为不是这样的。

【问题讨论】:

  • 当 operator dot 成为标准时,这很容易做到。
  • 那么at 会保留它的向量语义吗?另外,为什么myVec[ 1] 打印5 而不是10?如果向量为空会怎样?

标签: c++ inheritance boost vector stl


【解决方案1】:

这样的容器是否已经存在

至少不在标准库中。

是否可以重载或重新定义向量模板中的 [] 运算符?

不,您不能重载或重新定义 std::vector 的 [] 运算符。

当然可以编写具有您所描述行为的重载T&amp; operator[](int pos) 的包装器。像这样:

T& operator[](int pos) {
    std::vector<T>::size_type fancy_pos =
        pos < 0 ? data.size() + pos
                : pos - 1;
    return data[fancy_pos];
}

【讨论】:

    【解决方案2】:

    在 C++ 中,容器的索引从 0 开始。

    您可以将标准容器 std::vector 包装在一个类中并重载运算符 [],这样索引的计算方式类似于 index = index % size()index %= size()

    【讨论】:

      【解决方案3】:

      您正在寻找循环缓冲区或循环缓冲区。

      Boost 有它们:

      它们有时大大比例如使用 std::deque 滚动您自己,请参阅 ASIO 的此示例:


      更新

      我认为 boost::circular_buffer 可能是您/应该想要的/ - 因为它抽象了您通常想要的大多数任务的“如何”。但是,创建自己的适配器类型非常简单:

      Live On Coliru

      #include <vector>
      
      namespace mylib {
          template <typename T, typename Container = std::vector<T> >
          struct circular : Container {
              using Container::Container;
              using Container::operator =;
      
              auto& operator[](int i) const {
                  // mixed signed/unsigned modulo is undefined
                  while (i<0) i += Container::size();
                  return Container::operator[](i % Container::size());
              }
      
              auto& operator[](int i) {
                  while (i<0) i += Container::size();
                  return Container::operator[](i % Container::size());
              }
          };
      }
      
      #include <iostream>
      
      template <typename Whatever>
      void test(Whatever const& data) {
          std::cout << data[ 5] << ", "; // would output 15
          std::cout << data[ 1] << ", "; // would output 10
          std::cout << data[-2] << std::endl; // would output 10
      }
      
      #include <string>
      #include <deque>
      int main() {
          test(mylib::circular<int>                                   { 5, 10, 15                }); 
          test(mylib::circular<std::string>                           { "five", "teen", "fiteen" }); 
          test(mylib::circular<std::string, std::deque<std::string> > { "five", "teen", "fiteen" }); 
          test(mylib::circular<int, std::deque<float> >               { 5, 10, 15                }); 
      }
      

      打印:

      15, 10, 10
      fiteen, teen, teen
      fiteen, teen, teen
      15, 10, 10
      

      【讨论】:

      • 正如我在问题中所说,我已经看到了 Boost 循环缓冲区,但它并没有实现我想要的行为。
      • 我没看到。然而,它就是这样:Live On Coliru(注意模运算符周围的微妙之处)
      • 我不能使用 Boost 循环缓冲区的主要原因是它不接受 [0..n-1] 范围之外的索引。
      • 由于我对模板有点不熟悉:这基本上是在做我想要的吗?它“覆盖”了容器的 [] 运算符,并且仍然提供容器的所有其余接口?
      • 并不奇怪。你没有提到任何版本。我可以很容易地使它在任何版本中编译,它只是稍微不那么通用:c++11c++03。我的答案中的版本是c++14。请注意,C++03 不会自动公开原始接口的全部(因为不存在继承构造函数。您可能需要添加所需的构造函数)
      猜你喜欢
      • 2014-09-27
      • 1970-01-01
      • 1970-01-01
      • 2010-12-15
      • 2011-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多