Google Groups unterstützt keine neuen Usenet-Beiträge oder ‑Abos mehr. Bisherige Inhalte sind weiterhin sichtbar.

operator overloading

4 Aufrufe
Direkt zur ersten ungelesenen Nachricht

Michael Wild

ungelesen,
14.12.2005, 01:19:4514.12.05
an
Hi everybody

Is there any way to find out whether the return value of an overloaded
operator (such as []) is used as an lvalue or an rvalue? What I'm
getting at, is that I want to implement different behaviour for the
setter and getter (as you'd call them in languages with properties).

Thanks for any hints on how to implement this


- Michael

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Greg Herlihy

ungelesen,
14.12.2005, 07:02:4514.12.05
an

Michael Wild wrote:
> Hi everybody
>
> Is there any way to find out whether the return value of an overloaded
> operator (such as []) is used as an lvalue or an rvalue? What I'm
> getting at, is that I want to implement different behaviour for the
> setter and getter (as you'd call them in languages with properties).

Offer one overload that retrieves the value and another that can set
the value. The compiler can decide which one to use for given statement
in the source code:

struct myContainer
{
int& operator[](int index);
int operator[](int index) const;
...
};

and an example:

int main()
{
MyContainer c;
...

int i = c[4]; // gets a value from c
c[3] = 4; // sets value within c


Greg

Tom

ungelesen,
14.12.2005, 07:03:0714.12.05
an
Add a new object to encapsulate the return reference.
For exampel:
int& operator [] (int index) --> Integer operator[] (int index);
class Integer
{
int &m_integer;
public:
Integer(int &);
operator const int& () const; // For right value.
Integer& operator = (const int &); // For left value;
};

Andy

ungelesen,
14.12.2005, 07:03:5514.12.05
an
> Is there any way to find out whether the return value of an overloaded
> operator (such as []) is used as an lvalue or an rvalue?

You mean inside the function? No you can't. If I recall correctly,
there is such a feature in Perl. None in C++.

>What I'm
> getting at, is that I want to implement different behaviour for the
> setter and getter (as you'd call them in languages with properties).
>

Define separate getter and setter functions.

> Thanks for any hints on how to implement this
>

Maciej Sobczak

ungelesen,
14.12.2005, 07:55:0614.12.05
an
Michael Wild wrote:

> Is there any way to find out whether the return value of an overloaded
> operator (such as []) is used as an lvalue or an rvalue? What I'm
> getting at, is that I want to implement different behaviour for the
> setter and getter (as you'd call them in languages with properties).
>
> Thanks for any hints on how to implement this

Return a proxy object of some additional type that has differently
overloaded cast and assignment operators. The cast operator is called
when the value is read (in the context that provides the expected type,
at least) and the assignment operator will be called when the value is
written.
It's not really rvalue/lvalue distinction, but it's good enough to
imitate the "properties".

The following example implements the "property" and it might also give
you some hints on how to do similar tricks for operator[]:

#include <iostream>

template <class C, typename T, T (C::*get)() const, void (C::*set)(T
const &)>
class property
{
public:
property(C *obj) : obj_(obj) {}

operator T() const { return (obj_->*get)(); }
void operator=(T const &t) { (obj_->*set)(t); }

private:
C *obj_;
};

class C
{
private:
int get() const
{
std::cout << "reading\n";
return 7;
}

void set(int const &i)
{
std::cout << "writing " << i << '\n';
}

public:

C() : p(this) {}

property<C, int, &C::get, &C::set> p;
};


int main()
{
C c;

// write to "property"
c.p = 5;

// read from "property"
int i = c.p;
std::cout << i << '\n';
}

--
Maciej Sobczak : http://www.msobczak.com/
Programming : http://www.msobczak.com/prog/

PPD

ungelesen,
14.12.2005, 07:57:5614.12.05
an
I think several of Meyers' Effective C++ items discuss this. For
example, Item 18 (from 2nd Edition - Strive for class interfaces that
are complete and minimal) discusses the following:

I quote:

// return element for read/write
T& operator[](int index);
// return element for read-only
const T& operator[](int index) const;

By declaring the same function twice, once const and once non-const,
you provide support for both const and non-const Array objects. The
difference in return types is significant, as is explained in Item 21.

End of Quote.

You should check this and Item 21: Use const whenever possible.

That should answer your queries in this regard.

PPD

kanze

ungelesen,
14.12.2005, 10:42:1914.12.05
an
Maciej Sobczak wrote:
> Michael Wild wrote:

> > Is there any way to find out whether the return value of an
> > overloaded operator (such as []) is used as an lvalue or an
> > rvalue? What I'm getting at, is that I want to implement
> > different behaviour for the setter and getter (as you'd call
> > them in languages with properties).

> > Thanks for any hints on how to implement this

> Return a proxy object of some additional type that has
> differently overloaded cast and assignment operators. The cast
> operator is called when the value is read (in the context that
> provides the expected type, at least) and the assignment
> operator will be called when the value is written. It's not
> really rvalue/lvalue distinction, but it's good enough to
> imitate the "properties".

This works well for the basic types, or if the results are being
used as an atomic value (which is general all that is needed),
but it can fail for specific cases of class types. Expressions
like container[i].x can't be emulated, and even replacing . with
->, this doesn't provide a means of distinguishing between:
x = container[i]->x ;
and
container[i]->x = x ;
Even std::string has limitations:
char ch = container[i][0] ;
doesn't work, for example.

(The goal isn't to criticize your solution, which is, as far as
I know, the best available, and usually largely sufficient. But
it is worth pointing out a few limitations, just in case.)

--
James Kanze GABI Software
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

kanze

ungelesen,
14.12.2005, 10:42:4214.12.05
an
Greg Herlihy wrote:
> Michael Wild wrote:

> > Is there any way to find out whether the return value of an
> > overloaded operator (such as []) is used as an lvalue or an
> > rvalue? What I'm getting at, is that I want to implement
> > different behaviour for the setter and getter (as you'd call
> > them in languages with properties).

> Offer one overload that retrieves the value and another that
> can set the value.

What does that change? Overload resolution doesn't take into
account what you do with the results.

> The compiler can decide which one to use for given statement
> in the source code:

> struct myContainer
> {
> int& operator[](int index);
> int operator[](int index) const;
> ...
> };

> and an example:

> int main()
> {
> MyContainer c;
> ...

> int i = c[4]; // gets a value from c
> c[3] = 4; // sets value within c

Both uses call the same operator[].

See Maciej's posting for the correct solution.

--
James Kanze GABI Software
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

ahmet....@gmail.com

ungelesen,
14.12.2005, 10:43:2914.12.05
an
But when i test your code using:
m[1]=m[2];
cout<<m[3];
these commans, i saw only:
T& operator[](int index);
version is running.

Earl Purple

ungelesen,
14.12.2005, 10:47:4214.12.05
an

PPD wrote:
>
> // return element for read/write
> T& operator[](int index);
> // return element for read-only
> const T& operator[](int index) const;
>

> You should check this and Item 21: Use const whenever possible.


>
> That should answer your queries in this regard.

That won't quite answer his query because the compiler will choose the
non-const overload by default.

Now suppose he is trying to implement copy-on-write so when the calling
code modifies the element it can invoke copy-on-write.

For this you will need a special wrapper class, which will be needed
for the non-const version, which can then flag if any write method is
called, whether this be operator= or calling a non-const method.
Simplest when the type is a basic POD like char (copy-on-write strings)
as they have no methods and the only way of writing to them is
assignment.

Michael Wild

ungelesen,
14.12.2005, 15:41:0814.12.05
an
Earl Purple wrote:
> PPD wrote:
>> // return element for read/write
>> T& operator[](int index);
>> // return element for read-only
>> const T& operator[](int index) const;
>>
>
>> You should check this and Item 21: Use const whenever possible.
>>
>> That should answer your queries in this regard.
>
> That won't quite answer his query because the compiler will choose the
> non-const overload by default.
>
> Now suppose he is trying to implement copy-on-write so when the calling
> code modifies the element it can invoke copy-on-write.
>
> For this you will need a special wrapper class, which will be needed
> for the non-const version, which can then flag if any write method is
> called, whether this be operator= or calling a non-const method.
> Simplest when the type is a basic POD like char (copy-on-write strings)
> as they have no methods and the only way of writing to them is
> assignment.

Thanks for all the answers. The goal is actually to implement copy on
write functionality. As I'm operating on atomic types (float, double), I
hoped circumventing a proxy class is possible since I am reluctant to
accept the incurred overhead... But as it seems there's no other way and
nothing to do for it.

- Michael

0 neue Nachrichten