C++ 如何定义双括号/双迭代器运算符,类似于向量向量的向量';?

C++ 如何定义双括号/双迭代器运算符,类似于向量向量的向量';?,c++,vector,iterator,operator-overloading,deque,C++,Vector,Iterator,Operator Overloading,Deque,我正在移植使用非常大的浮点数数组的代码,这可能会触发从C到C++的Maloc故障。我问了一个关于是否应该使用Vector或deques的问题,并慷慨地向我提供了一个安全包装类型的示例: template<typename T> class VectorDeque { private: enum TYPE { NONE, DEQUE, VECTOR }; std::deque<T> m_d; std::vector<T> m_v; TYPE m_

我正在移植使用非常大的浮点数数组的代码,这可能会触发从C到C++的Maloc故障。我问了一个关于是否应该使用Vector或deques的问题,并慷慨地向我提供了一个安全包装类型的示例:

template<typename T>
class VectorDeque
{
private:
  enum TYPE { NONE, DEQUE, VECTOR };
  std::deque<T> m_d;
  std::vector<T> m_v;
  TYPE m_type;
  ...
public:
  void resize(size_t n)
  {
    switch(m_type)
    {
      case NONE:
      try
      {
        m_v.resize(n);
        m_type = VECTOR;
      }
      catch(std::bad_alloc &ba)
      {
        m_d.resize(n);
        m_type = DEQUE;
      }
      break;
    }
  }
};
最后一个大小安全的2D容器!!谢谢大家

如何使双括号过载? 我没有完全理解你的问题,但是你必须重载方括号,让它们返回一个重载自己的方括号操作符的对象

例如,如果您有一个向量向量,那么工作已经完成:
vector
重载
操作符[]
,它返回一个
向量
;这反过来又使其括号运算符重载(并返回一个
something
对象),因此您只需执行以下操作:

vector<vector<something> > vec;
// ...
something s = vec[2][3];
vec;
// ...
s=vec[2][3];

代理对象的示例:

template <typename T>
class Container
{
private:
    // ...


public:

    // Proxy object used to provide the second brackets
    template <typename T>
    class OperatorBracketHelper
    {
        Container<T> & parent;
        size_t firstIndex;
    public:
        OperatorBracketHelper(Container<T> & Parent, size_t FirstIndex) : parent(Parent), firstIndex(FirstIndex) {}

        // This is the method called for the "second brackets"
        T & operator[](size_t SecondIndex)
        {
            // Call the parent GetElement method which will actually retrieve the element
            return parent.GetElement(firstIndex, SecondIndex);
        }

    }

    // This is the method called for the "first brackets"
    OperatorBracketHelper<T> operator[](size_t FirstIndex)
    {
        // Return a proxy object that "knows" to which container it has to ask the element
        // and which is the first index (specified in this call)
        return OperatorBracketHelper<T>(*this, FirstIndex);
    }

    T & GetElement(size_t FirstIndex, size_t SecondIndex)
    {
        // Here the actual element retrieval is done
        // ...
    }
}
模板
类容器
{
私人:
// ...
公众:
//用于提供第二个括号的代理对象
模板
类运算符计数器
{
集装箱和母公司;
第一指数的大小;
公众:
OperatorBracketHelper(容器和父容器,大小\u t FirstIndex):父对象(父对象),FirstIndex(FirstIndex){}
//这是为“第二个括号”调用的方法
运算符[](大小\u T第二索引)
{
//调用父GetElement方法,该方法将实际检索元素
返回parent.GetElement(firstIndex,SecondIndex);
}
}
//这是为“第一个括号”调用的方法
运算符BracketOperator[](大小\u t第一索引)
{
//返回一个代理对象,该对象“知道”它必须向哪个容器请求元素
//哪个是第一个索引(在此调用中指定)
返回运算符rackethelper(*this,FirstIndex);
}
T&GetElement(大小\u T第一索引,大小\u T第二索引)
{
//这里是实际的元素检索
// ...
}
}
(在适当的情况下添加重载常量方法:)


请注意,对于
操作符()
实现,使用此方法几乎不会丢失任何东西,因为检索仍然在一个位置完成,对两个索引的使用没有限制,在执行检索时具有两个索引,并且不返回“fat”临时对象(
operatorBracketPer
与两个指针一样大,可以由编译器轻松优化)。

不要重载
[]
运算符,重载
()
运算符

请参阅此链接:

<>我建议在发布堆栈溢出之前至少通过一次C++ FAQ Lite,也可以搜索堆栈溢出,也可以得到一些有用的信息。

< P> C++中没有“双括号”运算符。你需要做的是定义一个单一的<代码> []运算符,并让它返回对另一个对象的引用,该对象反过来可以响应其自己的
[]
运算符。可以根据需要嵌套任意深度的层

例如,创建向量向量时,外部向量上的
[]
运算符返回对其中一个内部向量的引用;该向量上的
[]
运算符返回对向量的单个元素的引用

std::vector<std::vector<float> > example;
std::vector<float> & first = example[0];  // the first level returns a reference to a vector
float & second = example[0][0];  // the same as first[0]
std::向量示例;
std::vector&first=example[0];//第一级返回对向量的引用
float&second=示例[0][0];//与第一个[0]相同

有两种主要技术:

1) 使用运算符()而不是运算符[]。
这是因为运算符()允许多个参数

class My2D
{
    public:
       int&   operator()(int x,int y)  { return pget(x,y);}
    private:
       int&   pget(int x,int y) { /* retrieve data from 2D storage */ }
};
2) 使用运算符[],但返回中间对象。
然后可以将第二个运算符[]应用于中间对象

class My2D
{
    public:
       class My2DRow
       {
           My2D& parent;
           int   x;
           public:
               My2DRow(My2D& p, int theX) : parent(p), x(theX) {}     // Just init the temp object
               int& operator[](int y)  const { return parent.pget(x,y);}   // Here we get the value.
       };

       // Return an object that defines its own operator[] that will access the data.
       // The temp object is very trivial and just allows access to the data via operator[]
       My2DRow operator[](int x)        { return My2DRow(*this, x);}
    private:
       friend class My2DRow;
       int&   pget(int x,int y) { /* retrieve data from 2D storage */ }
};

int main()
{
    My2D   data;
    int&   val = data[1][2]; // works fine.

    // This is the same as
    My2D::My2DRow row  = data[1];
    int&          val2 = row[2]; 
}
我更喜欢第二种技巧。

这是因为它使原始代码保持不变,并且更易于阅读(在数组上下文中)。当然,您需要为实现2D数组的简单性付出更高的代价,因为实现2D数组的代码要稍微复杂一些。

我介绍了一个数组中多维数组的重载操作符[]


我可能会非常类似地处理迭代器:一个迭代器表示多维数组的“切片”(行或列),然后另一个迭代器表示该切片中的元素。

+1表示使用()。在实现多维索引时,它常常被忽略。(天知道我做过不止几次…:)浏览了那一部分和他的解决方案。它提到您可以使用[]。我读了他的推理,为什么你通常不想这样做,但我想保留它的向量ish/deque ish特性,所以我认为在这种情况下,它是值得的缺点。但是你会怎么做呢?他没有提供太多细节。我想我需要嵌套类或其他东西,但如何在这样的嵌套结构中保留try/catch处理?@Jason R.Mick:与C++常见问题解答中的许多内容一样,这是非常片面和主观的,我不同意。提供使用[][]使代码可读的能力是我推荐的方法,因为它使代码更易于阅读,从而更易于维护。(代价是让你的矩阵类稍微难读一点)。下面我提供了一个简单的模板,说明如何在不暴露实现细节的情况下实现它,从而提供灵活性(PS.这是一个相对标准的模式(不是我发明的))@LokiAstari虽然有点边缘化,但我要补充的是,除了更具可读性之外,使用[][]还保留了要在多维函子中使用的括号运算符。我用它来创建绑定,以便向opencl的n维范围内核空间发出参数。我希望能够使用双括号引用类型VectorDeque中包含的数据。你的例子与你的不同
class My2D
{
    public:
       int&   operator()(int x,int y)  { return pget(x,y);}
    private:
       int&   pget(int x,int y) { /* retrieve data from 2D storage */ }
};
class My2D
{
    public:
       class My2DRow
       {
           My2D& parent;
           int   x;
           public:
               My2DRow(My2D& p, int theX) : parent(p), x(theX) {}     // Just init the temp object
               int& operator[](int y)  const { return parent.pget(x,y);}   // Here we get the value.
       };

       // Return an object that defines its own operator[] that will access the data.
       // The temp object is very trivial and just allows access to the data via operator[]
       My2DRow operator[](int x)        { return My2DRow(*this, x);}
    private:
       friend class My2DRow;
       int&   pget(int x,int y) { /* retrieve data from 2D storage */ }
};

int main()
{
    My2D   data;
    int&   val = data[1][2]; // works fine.

    // This is the same as
    My2D::My2DRow row  = data[1];
    int&          val2 = row[2]; 
}