C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Using operator->

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language (comp.lang.c++)
View previous topic :: View next topic  
Author Message
Roger Leigh
Guest





PostPosted: Tue Jan 27, 2004 9:30 pm    Post subject: Using operator-> Reply with quote



I've written a simple container template class to contain a single
value. This emits a signal when the value is changed (it's used as a
notifier of changes), and listeners can connect to its changed signal.

i.e. field<int> i(2);
i = 4; // field<int>::m_value = 4; changed signal is emitted.

Currently, the contained value may be accessed via get_value() and
set_value() methods, and for ease of use, operator= and some type
conversions are provided. However, accessing a member function
requires a call to get_value(), and I'd like to overload operator->
and operator* to allow access. Ideally, I'd like a const version
(changes to the value are not allowed) and a non-const version, which
allows changes and emits a signal. However, I can't see that this is
possible (condensed for brevity):

template<typename T>
class field {
private:
value_type m_value;
SigC::Signal0<void> m_signal_changed; // libsigc++ signal type.
public:
typedef T value_type;

field(): m_value() {}
field(const value_type& value): m_value(value) {}
field(const field<value_type>& rhs): m_value(rhs.m_value),
m_signal_changed() {}
virtual ~field() {}

value_type& get_value() { return m_value; }
const value_type& get_value() const { return m_value; }

void set_value(const value_type& value)
{ m_value = value; m_signal_changed.emit(); }

field<value_type>& operator = (const field<value_type>& rhs)
{ set_value(rhs.m_value); return *this; }

field<value_type>& operator = (const value_type& rhs)
{ set_value(rhs); return *this; }

operator const value_type& () const { return m_value; }

SigC::Signal0<void>& signal_changed() { return m_signal_changed; }
}; // class field

If I provide a method like this:

const value_type *operator -> () { return &m_value; }

this is OK, but for the non-const version, I want to do this:

value_type *operator -> () { return &m_value; m_signal_changed() }

i.e. I want to emit the changed signal /after/ the caller has got the
pointer, used the method/member chosen and finished. If I emit the
signal before, the change won't yet have happened. However, I need to
return the pointer, so this is obviously impossible.

In addition, I'd like to make the const version the default (if a
const method is called from a non-const pointer), if possible, so that
the changed signal is only emitted on a genuine state change.

Are either of these possible using standard C++? If not, could anyone
suggest a different design to achieve the goal (signal emission after
value change)?


Many thanks,
Roger

--
Roger Leigh

Printing on GNU/Linux? http://gimp-print.sourceforge.net/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.


-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 100,000 Newsgroups - 19 Different Servers! =-----
Back to top
lilburne
Guest





PostPosted: Wed Jan 28, 2004 12:31 pm    Post subject: Re: Using operator-> Reply with quote





Roger Leigh wrote:
Quote:
i.e. I want to emit the changed signal /after/ the caller has got the
pointer, used the method/member chosen and finished. If I emit the
signal before, the change won't yet have happened. However, I need to
return the pointer, so this is obviously impossible.

In addition, I'd like to make the const version the default (if a
const method is called from a non-const pointer), if possible, so that
the changed signal is only emitted on a genuine state change.

Are either of these possible using standard C++? If not, could anyone
suggest a different design to achieve the goal (signal emission after
value change)?


You can't make the compiler use the const version of a function that is
overloaded on const alone i.e., the non-const method will always be
called on non-const objects. You have to differentiate the functions by
name i.e, rename non-const version of operator->() to be something like
get_value_to_change(). The long name encourages use of const values.

If you want to broadcast changes after the modification then you'll need
to use a set method and abandon the operator-> idea.


Back to top
Michael Mellor
Guest





PostPosted: Wed Jan 28, 2004 2:18 pm    Post subject: Re: Using operator-> Reply with quote



Roger Leigh wrote:
Quote:
I've written a simple container template class to contain a single
value. This emits a signal when the value is changed (it's used as a
notifier of changes), and listeners can connect to its changed signal.

i.e. field<int> i(2);
i = 4; // field<int>::m_value = 4; changed signal is emitted.

Currently, the contained value may be accessed via get_value() and
set_value() methods, and for ease of use, operator= and some type
conversions are provided. However, accessing a member function
requires a call to get_value(), and I'd like to overload operator-
and operator* to allow access. Ideally, I'd like a const version
(changes to the value are not allowed) and a non-const version, which
allows changes and emits a signal. However, I can't see that this is
possible (condensed for brevity):

template<typename T
class field {
private:
value_type m_value;
SigC::Signal0 public:
typedef T value_type;
This typedef needs to go before the line (value_type m_value).


Quote:

field(): m_value() {}
field(const value_type& value): m_value(value) {}
field(const field<value_type>& rhs): m_value(rhs.m_value),
m_signal_changed() {}
virtual ~field() {}


Are you not risking the value being changed and not having a signal
emitted with the following method.
Quote:
value_type& get_value() { return m_value; }

const value_type& get_value() const { return m_value; }

void set_value(const value_type& value)
{ m_value = value; m_signal_changed.emit(); }

field<value_type>& operator = (const field<value_type>& rhs)
{ set_value(rhs.m_value); return *this; }

field<value_type>& operator = (const value_type& rhs)
{ set_value(rhs); return *this; }

operator const value_type& () const { return m_value; }

SigC::Signal0<void>& signal_changed() { return m_signal_changed; }
}; // class field

If I provide a method like this:

const value_type *operator -> () { return &m_value; }

this is OK, but for the non-const version, I want to do this:

value_type *operator -> () { return &m_value; m_signal_changed() }

i.e. I want to emit the changed signal /after/ the caller has got the
pointer, used the method/member chosen and finished. If I emit the
signal before, the change won't yet have happened. However, I need to
return the pointer, so this is obviously impossible.

In addition, I'd like to make the const version the default (if a
const method is called from a non-const pointer), if possible, so that
the changed signal is only emitted on a genuine state change.

Are either of these possible using standard C++? If not, could anyone
suggest a different design to achieve the goal (signal emission after
value change)?

I am not sure I completely understood what you want but I will try. Are

you wanted to provide an operator-> for class field so that if T is a
structure you can access the individual fields? If so I don't think you
will be able to do that.

Michael Mellor

Back to top
Roger Leigh
Guest





PostPosted: Thu Jan 29, 2004 6:52 pm    Post subject: Re: Using operator-> Reply with quote

Michael Mellor <news-at- (AT) michaelmellor-dot- (DOT) com> writes:

Quote:
Roger Leigh wrote:

template<typename T
class field {
private:
value_type m_value;
SigC::Signal0 public:
typedef T value_type;

This typedef needs to go before the line (value_type m_value).

For what reason? Is this just a style issue? (Maybe this is just the C
programmer in me declaring everything before it's used?)

Quote:
field(): m_value() {}
field(const value_type& value): m_value(value) {}
field(const field<value_type>& rhs): m_value(rhs.m_value),
m_signal_changed() {}
virtual ~field() {}


Are you not risking the value being changed and not having a signal
emitted with the following method.
value_type& get_value() { return m_value; }

Yes, since this is the only possible way to call non-const methods in
contained compounds. If you call this, you need to manually emit the
changed signal (field<T>::signal_changed().emit()).

Quote:
const value_type& get_value() const { return m_value; }
void set_value(const value_type& value)
{ m_value = value; m_signal_changed.emit(); }
field<value_type>& operator = (const field<value_type>& rhs)
{ set_value(rhs.m_value); return *this; }
field<value_type>& operator = (const value_type& rhs)
{ set_value(rhs); return *this; }
operator const value_type& () const { return m_value; }
SigC::Signal0<void>& signal_changed() { return m_signal_changed;
}
}; // class field
If I provide a method like this:
const value_type *operator -> () { return &m_value; }
this is OK, but for the non-const version, I want to do this:
value_type *operator -> () { return &m_value; m_signal_changed()
}
i.e. I want to emit the changed signal /after/ the caller has got the
pointer, used the method/member chosen and finished. If I emit the
signal before, the change won't yet have happened. However, I need to
return the pointer, so this is obviously impossible.
In addition, I'd like to make the const version the default (if a
const method is called from a non-const pointer), if possible, so that
the changed signal is only emitted on a genuine state change.
Are either of these possible using standard C++? If not, could
anyone
suggest a different design to achieve the goal (signal emission after
value change)?

I am not sure I completely understood what you want but I will
try. Are you wanted to provide an operator-> for class field so that
if T is a structure you can access the individual fields? If so I
don't think you will be able to do that.

This is exactly what I want to do, and I agree with your conclusions.
What I've done is just provide an "operator -> () const", so it's
effectively read-only.

I've found a solution for non-const methods: If the contained class
uses the same signal mechanism as the field class (SigC++), I can
connect the changed signal of the contained class to the changed
signal of the field contained, so that the signal cascades, and I get
the behaviour I want. That is, I listen to the changed notification
and then notify my own listeners. This is useful, since it can nest
arbitrarily deeply for complex contained data structures.


Many thanks to you (and lilburne) for increasing my understanding!


Regards,
Roger

--
Roger Leigh

Printing on GNU/Linux? http://gimp-print.sourceforge.net/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.


-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 100,000 Newsgroups - 19 Different Servers! =-----

Back to top
Michael Mellor
Guest





PostPosted: Fri Jan 30, 2004 11:49 am    Post subject: Re: Using operator-> Reply with quote

Roger Leigh wrote:
Quote:
Michael Mellor <news-at- (AT) michaelmellor-dot- (DOT) com> writes:


Roger Leigh wrote:


template<typename T
class field {
private:
value_type m_value;
SigC::Signal0 public:
typedef T value_type;


This typedef needs to go before the line (value_type m_value).


For what reason? Is this just a style issue? (Maybe this is just the C
programmer in me declaring everything before it's used?)

What compiler do you use that allows a type to be used before the typedef?

I get:

$ g++ -Wall -pedantic c.cc
c.cc:4: error: 'value_type' is used as a type, but is not defined as a type.

and

"ComeauTest.c", line 4: error: identifier "value_type" is undefined
value_type m_value;

Michael Mellor

Back to top
Roger Leigh
Guest





PostPosted: Fri Jan 30, 2004 1:15 pm    Post subject: Re: Using operator-> Reply with quote

Michael Mellor <news-at- (AT) michaelmellor-dot- (DOT) com> writes:

Quote:
Roger Leigh wrote:
Michael Mellor <news-at- (AT) michaelmellor-dot- (DOT) com> writes:

Roger Leigh wrote:

template<typename T
class field {
private:
value_type m_value;
SigC::Signal0 public:
typedef T value_type;

This typedef needs to go before the line (value_type m_value).
For what reason? Is this just a style issue? (Maybe this is just
the C
programmer in me declaring everything before it's used?)

What compiler do you use that allows a type to be used before the typedef?
I get:

$ g++ -Wall -pedantic c.cc
c.cc:4: error: 'value_type' is used as a type, but is not defined as a type.

and

"ComeauTest.c", line 4: error: identifier "value_type" is undefined
value_type m_value;

My apologies--I moved the private part of the class to the top in my
posting to make the problem clearer. It's actually right at the
bottom. I'm using GCC 3.3.3.

The full class (licence boilerplate stripped) is:
// database field container -*- C++ -*-
#ifndef PQXX_OBJECT_FIELD_H
#define PQXX_OBJECT_FIELD_H

#include <sigc++/signal.h>

namespace pqxxobject
{
/**
* Database field template class.
* This class is used to represent a single field in a row of a
* table. This is a single value belonging to a column in a row,
* rather than the whole column.
*
* As well as storing value, the class has the ability to emit
* signals when the field value is changed. Listeners (e.g. user
* interface widgets) may connect to the signal and will receive
* notification of changes as they occur.
*/
template<typename T>
class field
{
public:
typedef T value_type;

/// The constructor.
field():
m_value()
{}

/// The constructor.
field(const value_type& value):
m_value(value)
{}

/// The copy constructor.
field(const field<value_type>& rhs):
m_value(rhs.m_value),
m_signal_changed()
{}

virtual ~field()
{}

/// Access member functions.
const value_type *operator -> () const
{
return &m_value;
}

const value_type& operator * () const
{
return m_value;
}

/// Overloaded assignment operator.
field<value_type>& operator = (const field<value_type>& rhs)
{
set_value(rhs.m_value);
return *this;
}

/// Overloaded assignment operator.
field<value_type>& operator = (const value_type& rhs)
{
set_value(rhs);
return *this;
}

/// Conversion operator.
operator const value_type& () const
{
return m_value;
}

/**
* Get the contained value by reference.
* @returns a reference to the value.
*/
value_type& get_value()
{
return m_value;
}

/**
* Get the contained value by constant reference.
* @returns a constant reference to the value.
*/
const value_type& get_value() const
{
return m_value;
}

/**
* Set the contained value.
* @param value the value to set.
*/
void set_value(const value_type& value)
{
m_value = value;
m_signal_changed.emit();
}

/**
* Signal emitted on value change.
* @returns the signal.
*
* For example:
* @code
* field<int> col;
* someclass listener;
* col.signal_changed().connect
* ( SigC::slot(listener, &someclass::on_col_changed() );
* @endcode
* i.e. a class method (listener.on_col_changed()) will be called
* when the value is changed.
*/
SigC::Signal0<void>& signal_changed()
{
return m_signal_changed;
}

private:
/// The contained value.
value_type m_value;
/// The changed signal.
SigC::Signal0<void> m_signal_changed;

}; // class field

}; // namespace pqxxobject

#endif // PQXX_OBJECT_FIELD_H


--
Roger Leigh

Printing on GNU/Linux? http://gimp-print.sourceforge.net/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.


-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 100,000 Newsgroups - 19 Different Servers! =-----

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language (comp.lang.c++) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.