Operator () overloading, wrong overload gets called

F

fabian.lim

Hi all,

Im having a problem with my code. Im programming a vector class,
and am trying to overload the () operator in 2 different situations.
The first situation is to assign values, e.g. Y = X(1,2), the elements
1 and 2 of X gets assigned to Y. In this case, the operator ()
overload should create a copy that is unmodifiable. In the 2nd case, I
want do assign values to elements 1 and 2, e.g. X(1,2) = Y. Then in
this case, the values must be updated. I update by instantiating a
custom iterator class which has an overloaded = operator. Below is my
code. Sorry its a little long.

The issue now is that when I do Y = X(1,2), I always end up calling
the overload that is meant for the 2nd situation, rather than the
first. I hope I can get some advice.

Thanks in advance.

//********************************************************
// Main Vector Class
template <typename TYPE>
class Vector {
vector<TYPE> v;
public:
//********************************************************
// Selectors
const TYPE& operator[](const int& k) const { return v[k]; } //default
[] indexing
const TYPE& operator()(const int& k) const {return v[k];}
int size() const {return v.size();} //returns the size

//********************************************************
// VectorItr Class
// this is a custom iterator class for Vector
// it wraps the standard vector iterator class
class VectorItr : public
std::iterator<std::random_access_iterator_tag, TYPE> {
typename vector<TYPE>::iterator vitr;
int n; int *ptr;
public:

//assignments
VectorItr& operator= (const Vector<TYPE>& rhs) {
//using the iterator, populate the Vector<TYPE>
if (ptr == NULL) //for range
rhs.assign(vitr,n,rhs);
else {
for (int k=0; k<n; k++)
*(vitr+ptr[k]) = rhs[k];
}
return *this; //should i return this?
}

//********************************************************
// Constructors and Destructor
VectorItr() { };
~VectorItr(){ };

VectorItr( Vector<TYPE>& val, const int& i, const int& j) {
//this is used for range assignment
//this constructor is used to initialize the beginning of the
//iterator, and the number of elements that need to be assigned
vitr = val.begin()+i; n = j-i+1; ptr = NULL;
}

VectorItr( Vector<TYPE>& val, int ind[], const int n2) {
//this is used for index assignment
//this constructor is used to initialize the beginning of the
//iterator, and the number of elements that need to be assigned
vitr = val.begin(); n = n2; ptr = &ind[0];
}

};

const Vector<TYPE> operator()(const int& i, const int& j) const
{
return Vector<TYPE>(*this, i, j);
}

VectorItr operator()(const int& i, const int& j)
{
return VectorItr (*this, i, j);
}

//********************************************************
// Constructors and Destructor
Vector() { };
~Vector(){ };

//********************************************************
// Copiers
//copy constructors
Vector( const Vector<TYPE>& val) { //copy constructor for
intermediate results (like x + y)
for (int k = 0; k < val.size(); k++)
v.push_back(val[k]);
}
Vector( const Vector<TYPE>& val, const int& i, const int& j) {
//this constructor is used to create copy when indexing a range
for (int k = i; k <=j; k++){
if (k<val.size())
v.push_back(val[k]);
else v.push_back(0);
}
}
//can i make an initialization that does something like v = {1, 2 3};

//assignments
Vector<TYPE>& operator=(const Vector<TYPE>& rhs) {
v.clear();
for (int k = 0; k < rhs.size(); k++)
v.push_back(rhs[k]);
return *this;
}

//********************************************************
// vector container functions
void push_back(TYPE val) {v.push_back(val);}
typename vector<TYPE>::iterator begin() { return v.begin();}
typename vector<TYPE>::iterator end() { return v.end();}
void assign(typename vector<TYPE>::iterator itr, const int& n, const
Vector<TYPE>& val) const {
//Maybe I should group this under copiers
for (int k=0; k<n; k++){
*itr = val[k]; itr++;
}
//return *this; //should i return this?
}

template <size_t N> //trick to get array size in automatically!
Vector<TYPE>& assign(int (&val)[N]) {
v.assign(val, val+N);
return *this;
}


};
 
J

James Kanze

Im having a problem with my code. Im programming a vector
class, and am trying to overload the () operator in 2
different situations. The first situation is to assign
values, e.g. Y = X(1,2), the elements 1 and 2 of X gets
assigned to Y. In this case, the operator () overload should
create a copy that is unmodifiable. In the 2nd case, I want do
assign values to elements 1 and 2, e.g. X(1,2) = Y. Then in
this case, the values must be updated. I update by
instantiating a custom iterator class which has an overloaded
= operator. Below is my code. Sorry its a little long.
The issue now is that when I do Y = X(1,2), I always end up
calling the overload that is meant for the 2nd situation,
rather than the first. I hope I can get some advice.

I've not plunged into your code, but the standard solution here
is for the operator() to return a proxy. (I did something like
this in my pre-standard string class, which allowed:
s( n, m ) = ... ;
for
s = s.replace( n, m, ... ) ;
..) Basically, you still need two operator(): one const (in
order to be able to call it on a const object), and one
non-const. The const one can return the sub-vector directly,
but the non-const one must return a proxy. Basically, the proxy
just stores the relevant information, and overloads its
operator= so that it actually does the expected assign.
Something like:

class Proxy // should be a member of Vector
{
public:
Proxy( Vector& v, int i, int j )
: owner( &v ), i( i ), j( j )
{
}

// For conversion to rvalue...
operator Vector() const
{
return Vector( *owner, i, j ) ;
}

// For v1 = v2( i, j ) ;
Vector& operator=( Vector const& other )
{
owner->v.erase( v.begin() + i, v.begin() + j ) ;
owner->v.insert( v.begin() + i, other.begin(),
other.end() ) ;
return *owner ;
}
} ;

Or something along those lines.
 
F

fabian.lim

Hi James,

Thanks for replying my post again. I am doing the proxy thing, that
is done by the VectorItr Class. Essentially my code works only in the
following situation:

template <typename TYPE>
void ModifyValues(const Vector<TYPE>& x){
Vector<int> y;
//put in some values into y.. lets say {3,4}
y = x(0,1);
}

int main (){

Vector<int> x;
//put in some values into x.. lets say { 0, 1, 2}

//try to index 2 values of x and change y
return 0;
}

In this situation, Vector x is passed into the function ModifyValues()
as a const, thus the const overloaded () operator will kick in.

However, in the following situation, it will not work:
int main (){

Vector<int> x,y;
//put in some values into x.. lets say { 0, 1, 2}

//put in some values into y.. lets say {3,4}

//try to index 2 values of x and change y
y = x(0,1); <---- doesnt work, will call the non-const version
of the operator() overload

x(0,1) = y; <------ however this works.

return 0;
}

If I do not pass Vector x into a function, and specify it to be const,
the const overload never kicks in.

Thanks
 
J

James Kanze

I am doing the proxy thing, that is done by the VectorItr
Class.

Apparently not correctly.
Essentially my code works only in the following situation:

template <typename TYPE>
void ModifyValues(const Vector<TYPE>& x){
Vector<int> y;
//put in some values into y.. lets say {3,4}
y = x(0,1);
}
int main (){
Vector<int> x;
//put in some values into x.. lets say { 0, 1, 2}
//try to index 2 values of x and change y
return 0;
}
In this situation, Vector x is passed into the function
ModifyValues() as a const, thus the const overloaded ()
operator will kick in.
However, in the following situation, it will not work:
int main (){
Vector<int> x,y;
//put in some values into x.. lets say { 0, 1, 2}
//put in some values into y.. lets say {3,4}
//try to index 2 values of x and change y
y = x(0,1); <---- doesnt work, will call the non-const version
of the operator() overload

Which is correct. Overload resolution is determined uniquely by
the types, and since the type of x is not const, you get the
non-const operator().

This is where the proxy kicks in. The non const version has
returned a proxy, not a Vector. Supposing that the assignment
operator of Vector requires a Vector, you need a conversion. So
you define a user defined conversion to Vector in the proxy
class, which returns whatever the const operator() would have
returned.
x(0,1) = y; <------ however this works.
return 0;
}
If I do not pass Vector x into a function, and specify it to
be const, the const overload never kicks in.

Which it shouldn't. It's up to you to make the proxy work
correctly in rvalue contexts. (Look at the example code I
posted. Or better yet, read up on proxies---if memory serves me
right, Scott Meyers discusses them in one of his books.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top