我正在移植使用大量浮点数的代码,这可能会触发从c到c ++的malloc失败。我问了一个关于我是否应该使用矢量或者deques的问题,Niki Yoshiuchi慷慨地给了我这个安全包装类型的例子:
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矢量/ deque deques的矢量,所以我把它修改为以下代码:
template<typename T>
class VectorDeque
{
private:
enum STORAGE_CONTAINER { NONE, DEQUE, VECTOR };
std::deque<std::deque<T> > x_d,y_d,z_d;
std::vector<std::vector<T> > x_v,y_v,z_v;
TYPE my_container;
public:
void resize(size_t num_atoms, size_t num_frames)
{
switch(m_type)
{
case NONE:
try
{
x_v.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
x_v[counter].resize(num_frames);
y_v.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
y_v[counter].resize(num_frames);
z_v.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
z_v[counter].resize(num_frames);
my_container = VECTOR;
}
catch(std::bad_alloc &e)
{
x_d.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
x_d[counter].resize(num_frames);
y_d.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
y_d[counter].resize(num_frames);
z_d.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
z_d[counter].resize(num_frames);
my_container = DEQUE;
}
break;
}
}
};
我现在希望能够定义括号运算符,以便我可以使用类似的语句
x[1][2]
直接访问我正在使用的真实内存容器中的任何一个(由我的枚举变量的值给出。
我已经看到了几个关于覆盖括号运算符的教程,但我们不知道要覆盖双括号。
如何重载双括号?
另外,如何重载双迭代器(如果我想使用迭代器,而不是直接索引)?
编辑1:
根据Martin York / Matteo Italia的解决方案,我设计了以下课程:
template<typename T>
class VectorDeque2D
{
public:
class VectorDeque2D_Inner_Set
{
VectorDeque2D& parent;
int first_index;
public:
// Just init the temp object
VectorDeque2D_Inner_Set(My2D& p, int first_Index) :
parent(p),
first_Index(first_index) {}
// Here we get the value.
T& operator[](int second_index) const
{ return parent.get(first_index,second_index);}
};
// 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[]
VectorDeque2D_Inner_Set operator[](unsigned int first_index) {
return (*this, x);
}
void resize_first_index(unsigned int first_index) {
try {
my_vector.resize(first_index);
my_container = VECTOR;
}
catch(std::bad_alloc &e) {
my_deque.resize(first_index);
my_container = DEQUE;
}
}
void resize_second_index(unsigned int second_index) {
try {
for (unsigned int couter=0;couter < my_vector.size(); counter++) {
my_vector[counter].resize(second_index);
}
my_container = VECTOR;
}
catch(std::bad_alloc &e) {
for (unsigned int couter=0;couter < my_deque.size(); counter++) {
my_deque[counter].resize(second_index);
}
my_container = DEQUE;
}
}
void resize(unsigned int first_index,
unsigned int second_index) {
try {
my_vector.resize(first_index);
for (unsigned int couter=0;couter < my_vector.size(); counter++) {
my_vector[counter].resize(second_index);
}
my_container = VECTOR;
}
catch(std::bad_alloc &e) {
my_deque.resize(first_index);
for (unsigned int couter=0;couter < my_deque.size(); counter++) {
my_deque[counter].resize(second_index);
}
my_container = DEQUE;
}
}
private:
enum STORAGE_CONTAINER { NONE, DEQUE, VECTOR };
friend class VectorDeque2D_Inner_Set;
std::vector<std::vector<T> > my_vector;
std::deque<std::deque<T> > my_deque;
STORAGE_CONTAINER my_container;
T& get(int x,int y) {
T temp_val;
if(my_container == VECTOR) {
temp_val = my_vector[first_index][second_index];
}
else if(my_container == DEQUE) {
temp_val = my_deque[first_index][second_index];
}
return temp_val;
}
};
最后一个尺寸安全的2D容器!!谢谢你们!
答案 0 :(得分:20)
有两种主要技术:
1)使用operator()而不是operator []。
这是因为operator()允许多个参数。
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)使用operator []但返回一个中间对象 然后,您可以将第二个运算符[]应用于中间对象。
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阵列的稍微复杂的代码付出高级别的简单性。
答案 1 :(得分:4)
如何重载双括号?
我没有完全理解你的问题,但你必须重载括号,并让它们返回一个重载其自己的括号运算符的对象。
例如,如果你有一个向量向量,那么工作已经完成:vector < vector < something > >
重载operator[]
,它返回vector< something >
;反过来,它的括号运算符被重载(它返回一个something
对象),所以你可以这样做:
vector<vector<something> > vec;
// ...
something 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
// ...
}
}
(在适当的地方添加重载的const方法:))
请注意,使用此方法,您在operator()
实现方面几乎不会丢失任何内容,因为检索仍然在一个地方完成,而不会限制两个索引的使用,目前同时具有两个索引执行检索,而不返回“胖”临时对象(OperatorBracketHelper
就像两个指针一样大,并且可以很容易地被编译器优化掉。)
答案 2 :(得分:2)
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]
答案 3 :(得分:1)
不要重载[]
运算符,使()
运算符重载。
请参阅此链接:Overloading Subscript Operator.
我强烈建议您在发布到Stack Overflow之前至少阅读一次C ++ FAQ Lite。此外,搜索Stack Overflow也可能会产生一些有用的信息。
答案 4 :(得分:0)
我为answer to a previous question中的多维数组覆盖了operator []。
我可能非常类似地处理迭代器:有一个迭代器代表多维数组的“切片”(行或列),然后是另一个代表该切片中元素的迭代器。