using array operators for lvalue and rvalue?

U

usao

Does anyone have an example of how to create a class which describes
and array, such that I can use the subscript operator[] on both the
left and right side of an assignment statement? This is as close as I
can get, but I feel it's kludgey and slow...

#include <iostream.h>

template<class T>
class foo {
T *data;

public:
foo(int size) { data=new T[size]; }
~foo() { delete[] data; }

class helper {
T &item;
public:
helper(T &item_) : item(item_) {}
T &operator=(const T& other) {
cout <<"nonconst used as lvalue\n";
item=other;
return item;
}
operator const T&() const {
cout <<"nonconst used as rvalue\n";
return item;
}
};

helper operator[](int index) {
//don't know yet whether we are being used as l or r value
return helper(data[index]);
}
const T& operator[](int index) const {
cout <<"const used as rvalue\n";
return data[index];
}
};


int main()
{
foo<int> x(10);
const foo<int> &y=x;

cout <<"--- performing x[3]=10\n";
x[3]=10; //OK: nonconst used as lvalue

//cout <<"y[3]=11\n";
//y[3]=11; //BAD: const used as lvalue

cout <<"--- performing a=x[3]\n";
int a=x[3]; //OK: nonconst used as rvalue

cout <<"--- performing b=y[3]\n";
int b=y[3]; //OK: const used as rvalue

cout <<"--- performing x[3]=x[3]+5\n";
x[3]=x[3]+5; //OK: nonconst used as rvalue, then as lvalue

cout <<"result: x3 is " <<x[3] <<"\n";

return 0;
}
 
E

Erik Wikström

Does anyone have an example of how to create a class which describes
and array, such that I can use the subscript operator[] on both the
left and right side of an assignment statement? This is as close as I
can get, but I feel it's kludgey and slow...

Perhaps I do not quite understand what you are asking for but something
like this should work:

class Foo
{
int i_;
public:
int& operator[](int i) { return 1; } // Replace 1 with a real element
};

int main()
{
Foo f;
f[1] = 1;
int i = f[1];
}
 
U

usao

Does anyone have an example of how to create a class which describes
and array, such that I can use the subscript operator[] on both the
left and right side of an assignment statement? This is as close as I
can get, but I feel it's kludgey and slow...

Perhaps I do not quite understand what you are asking for but something
like this should work:

class Foo
{
  int i_;
public:
  int& operator[](int i) { return 1; } // Replace 1 with a real element

};

int main()
{
  Foo f;
  f[1] = 1;
  int i = f[1];

}

So, this can be done without the helper class?
 
U

usao

It compiles and runs fine on my Solaris host, but as for speed, I have
another really kludgey and unreadable C program which does basically
the same thing using function calls rather than array subscripting.
The C program (compiled with gcc) runs approx 200 times faster than
the C++ program (compiled with g++). I think the issue is around the
test for the const values which I have in the helper class. That seems
to add an extra layer of complexity which I don't worry about in the C
code.
But, hey, i fully admit that I dont know everything, and if there is a
better way to do this, that's what im looking for, so I can learn
somthing...

"Slow"?  Did you measure it?  How slow is it?  And compared to what?
#include <iostream.h>

There is no such header.
[.. idiomatic implementation of a proxy object returned by op[] ..]

That's not the only way to do it, but pretty much the "standard" approach.

V
 
J

jason.cipriani

So, this can be done without the helper class?

Yes. Do what Erik says. The [] operator returns a reference to an
element in the array; and so modifying values through that reference
directly modifies the data in the array.

You would probably want to do this as well, though:

template <class T> class foo {
public:
T& operator [] (int index) { return data_[index]; }
const T& operator [] (int index) const { return data_[index]; }
private:
T *data_; // <-- allocated by something
};

void f () {
foo<std::string> x;
x[4] = x[0];
x[7] = "string";
std::string::const_iterator = x[8].begin();
}

Provide both a const and non-const version of the [] operator and the
compiler will use the appropriate one when necessary, you do not need
to think about it.

Also note that std::vector<> exists and wraps an array. Depending on
your situation and requirements you may be able to save yourself some
future troubles by using the std implementation instead.

Jason
 
J

jason.cipriani

It compiles and runs fine on my Solaris host,

It *happens* to compile find. And if the only machines you are
compiling it on have that header then, well, it does get the job done.

However, of course, sticking to the standards will increase
portability, which decreases kludginess and decreases future problems.
Modern C++ defines the correct header to be <iostream>. Using the
standard headers gives you future benefit with zero cost (find-replace
will be your friend if you change this in a large existing project).
The C program (compiled with gcc) runs approx 200 times faster than
the C++ program (compiled with g++). I think the issue is around the
test for the const values which I have in the helper class. That seems
to add an extra layer of complexity which I don't worry about in the C
code.

I can't speak for the speed. If you could provide full source and
compiler command lines for simple C and C++ code to use as a bench
mark, you might get some good insights here. However, the extra layer
of complexity is not actually necessary (see other reply). Returning
references to objects in the array from your [] operator provides
direct access to the data in the array. Providing both a const and non-
const implementation (as in other reply) gives you the flexibility you
want.


Jason
 
K

Kai-Uwe Bux

usao said:
Does anyone have an example of how to create a class which describes
and array, such that I can use the subscript operator[] on both the
left and right side of an assignment statement? This is as close as I
can get, but I feel it's kludgey and slow...

Perhaps I do not quite understand what you are asking for but something
like this should work:

class Foo
{
int i_;
public:
int& operator[](int i) { return 1; } // Replace 1 with a real element

};

int main()
{
Foo f;
f[1] = 1;
int i = f[1];

}

So, this can be done without the helper class?

Yes. However, _sometimes_ proxy object offer additional benefits. E.g., if
you want to implement copy-on-write semantics, an exposed non-const
reference can be cumbersome. In that case, a proxy object would be the way
to go. Otherwise, it will just add unnecessary complexity.


Best

Kai-Uwe Bux
 

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,764
Messages
2,569,564
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top