[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

Operator () overloading, wrong overload gets called

fabian.lim

9/10/2008 6:36:00 AM

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;
}


};
3 Answers

James Kanze

9/10/2008 9:19:00 AM

0

On Sep 10, 8:35 am, fabian....@gmail.com wrote:
> 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.

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

fabian.lim

9/10/2008 9:44:00 AM

0

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

On Sep 9, 11:19 pm, James Kanze <james.ka...@gmail.com> wrote:
> On Sep 10, 8:35 am, fabian....@gmail.com wrote:
>
> > 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.
>
> --
> James Kanze (GABI Software) email:james.ka...@gmail.com
> Conseils en informatique orientée objet/
> Beratung in objektorientierter Datenverarbeitung
> 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

James Kanze

9/10/2008 4:09:00 PM

0

On Sep 10, 11:43 am, fabian....@gmail.com wrote:

> 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.)

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34