Defining a cast on a templated class

A

alan

I'm creating a sort-of "wrapper" class which (partly) acts like a
variable. Something like:
template<class t>
class cell{
t curval;
public:
/*public for debugging only - will be private in final version*/
inline cell<t>& set_value(t v){ curval = v; return *this;}
inline t get_value(){ return curval;}
/*actual public interface*/
/*assign to this value*/
inline cell<t>& operator=(t v){ return set_value(v);}
};
....
int
main(void){
cell<int> v;
v = 0;
cout << "v = " << ((int)v);
return 0;
}

However I can't figure out how to make the compiler do v.get_value()
when v is used in an int() context. Since this is templated, the only
conversion I want to support is something like cell<type> -> type.
Attempts to convert to unrelated types should signal an error.

I can't figure out the correct syntax to do this, unfortunately
(should probably look for better manuals, sigh).

----

In any case the actual target would be something like this:
int
main(void){
cell<int> v;
cell<int> v2;
v = v2 + 1; //v automatically changes when v2 is changed
v2 = 3;
if((int)v == 4){
cout << "Test 1 passed\n";
} else{
cout << "Test 1 failed\n";
return 1;
}
v2 = 4;
if((int)v == 5){
cout << "Test 2 passed\n";
} else{
cout << "Test 2 failed\n";
return 1;
}
return 0;
}

Basically the cell<> class would be like a spreadsheet cell - when I
assign a formula into it, its value will be automatically updated if
any of the cells in the formula are updated.

The way I intend to implement it is, I extend +-*/ and ?: so that if
any cells are in any parameters, they will instead return a new cell
which registers itself to the input cells. Something like:
template<class t>
cell<t>& operator+(cell<t> v1, t v2){
sum_cell<t> *sum = new sum_cell<t>(v2);
sum.register_yourself_to(v1); //when v1 is update()d, sum's update()
method is called
return (cell<t>&) *sum;
}

If there is already some existing library that does (in some form) the
above, please inform me. I suspect there already is, somehow I have a
feeling I've seen it before.
 
A

Alf P. Steinbach

* alan:
I'm creating a sort-of "wrapper" class which (partly) acts like a
variable. Something like:
template<class t>
class cell{
t curval;
public:
/*public for debugging only - will be private in final version*/
inline cell<t>& set_value(t v){ curval = v; return *this;}
inline t get_value(){ return curval;}
/*actual public interface*/
/*assign to this value*/
inline cell<t>& operator=(t v){ return set_value(v);}
};
...
int
main(void){
cell<int> v;
v = 0;
cout << "v = " << ((int)v);
return 0;
}

However I can't figure out how to make the compiler do v.get_value()
when v is used in an int() context. Since this is templated, the only
conversion I want to support is something like cell<type> -> type.
Attempts to convert to unrelated types should signal an error.

You can't avoid built-in conversions, e.g. int -> double.

So the technical answer 'operator type() const' is not a practical one.

There are also other reasons (overloading, not doing things behind the
client code programmer's back) that mean that an implicit conversion is
generally ungood.

Instead just provide a named member function.


I can't figure out the correct syntax to do this, unfortunately
(should probably look for better manuals, sigh).

----

In any case the actual target would be something like this:
int
main(void){
cell<int> v;
cell<int> v2;
v = v2 + 1; //v automatically changes when v2 is changed
v2 = 3;
if((int)v == 4){
cout << "Test 1 passed\n";
} else{
cout << "Test 1 failed\n";
return 1;
}
v2 = 4;
if((int)v == 5){
cout << "Test 2 passed\n";
} else{
cout << "Test 2 failed\n";
return 1;
}
return 0;
}

Basically the cell<> class would be like a spreadsheet cell - when I
assign a formula into it, its value will be automatically updated if
any of the cells in the formula are updated.

The way I intend to implement it is, I extend +-*/ and ?: so that if
any cells are in any parameters, they will instead return a new cell
which registers itself to the input cells. Something like:
template<class t>
cell<t>& operator+(cell<t> v1, t v2){
sum_cell<t> *sum = new sum_cell<t>(v2);
sum.register_yourself_to(v1); //when v1 is update()d, sum's update()
method is called
return (cell<t>&) *sum;
}

If there is already some existing library that does (in some form) the
above, please inform me. I suspect there already is, somehow I have a
feeling I've seen it before.

Perhaps look at the Open Office source?

Cheers, & hth.,

- Alf
 
A

Alexey Stepanyan

I'm creating a sort-of "wrapper" class which (partly) acts like a
variable. Something like:
template<class t>
class cell{
t curval;
public:
/*public for debugging only - will be private in final version*/
inline cell<t>& set_value(t v){ curval = v; return *this;}
inline t get_value(){ return curval;}
/*actual public interface*/
/*assign to this value*/
inline cell<t>& operator=(t v){ return set_value(v);}};

...
int
main(void){
cell<int> v;
v = 0;
cout << "v = " << ((int)v);
return 0;

}

However I can't figure out how to make the compiler do v.get_value()
when v is used in an int() context. Since this is templated, the only
conversion I want to support is something like cell<type> -> type.
Attempts to convert to unrelated types should signal an error.

I can't figure out the correct syntax to do this, unfortunately
(should probably look for better manuals, sigh).
1) all methods defined in class are implicitly inline so
explicit "inline" is obsolete

2) it's better to pass parameters by const ref to operator= and
set_value
because they don't modify the input value. Also get_value should be
const

3) use conversion operator to provide a conversion from cell<t> to t

operator T() const
{
return curval;
}

to provide a conversion from t to cell<t> you can define a one
parameter constructor
( conversion constructor )

cell( const t& curval_ ):curval( curval_ )
{}
 
A

alan

* alan:





You can't avoid built-in conversions, e.g. int -> double.
Err, what I meant was, not able to do something really dumb, like
cell said:
So the technical answer 'operator type() const' is not a practical one.
That's what I was looking for, thanks!
There are also other reasons (overloading, not doing things behind the
client code programmer's back) that mean that an implicit conversion is
generally ungood.

Instead just provide a named member function.
Hmm. I suppose this is possible since I intend to use it very rarely
anyway.
Still, I think operator type() is good.
Perhaps look at the Open Office source?
Hmm.
I just want to be able to do something like:

cell<int> CON, baseCON, inventoryCON, wornCON;

void
declarations(void){
size_t i;
CON = baseCON + inventoryCON + wornCON;
inventoryCON = 0; wornCON = 0;
for(i = 0; i < 52; i++){
inventoryCON = inventoryCON + inventory.CONbonuswhencarried;
wornCON = wornCON +
inventory.worn ? inventory.CONbonuswhenworn :
/*else*/ 0 ;
}
}
Then at any point, all I need to ask for CON, without having to
explicitly perform the computation myself each time the inventory
changes, items are worn/unworn, etc.
Is ?: overloadable?
Although of course there will probably be 5 other stats, so I'll be
thinking how to do that (maybe put stats as an array too).
 
A

alan

1) all methods defined in class are implicitly inline so
explicit "inline" is obsolete hehe.


2) it's better to pass parameters by const ref to operator= and
set_value
because they don't modify the input value. Also get_value should be
const Thanks for the tip!

3) use conversion operator to provide a conversion from cell<t> to t

operator T() const
{
return curval;
}
Yes, stumbled on this afterwards.
to provide a conversion from t to cell<t> you can define a one
parameter constructor
( conversion constructor )

cell( const t& curval_ ):curval( curval_ )
{}
Hmm.
 
M

Michael DOUBEZ

Alf P. Steinbach a écrit :
* alan:
I'm creating a sort-of "wrapper" class which (partly) acts like a
variable. Something like:
template<class t>
class cell{
t curval;
public:
/*public for debugging only - will be private in final version*/
inline cell<t>& set_value(t v){ curval = v; return *this;}
inline t get_value(){ return curval;}
/*actual public interface*/
/*assign to this value*/
inline cell<t>& operator=(t v){ return set_value(v);}
};
[snip: answered]

Basically the cell<> class would be like a spreadsheet cell - when I
assign a formula into it, its value will be automatically updated if
any of the cells in the formula are updated.

The way I intend to implement it is, I extend +-*/ and ?: so that if
any cells are in any parameters, they will instead return a new cell
which registers itself to the input cells. Something like:
template<class t>
cell<t>& operator+(cell<t> v1, t v2){
sum_cell<t> *sum = new sum_cell<t>(v2);
sum.register_yourself_to(v1); //when v1 is update()d, sum's update()
method is called
return (cell<t>&) *sum;
}

If there is already some existing library that does (in some form) the
above, please inform me. I suspect there already is, somehow I have a
feeling I've seen it before.

Perhaps look at the Open Office source?

It is straightforward to use boost::function0<T>(), boost::ref() and
boost::bind() to compose your elements.

#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#include <iostream>
#include <functional>
#include <cassert>

//use with boost::function0<T> to return constant value
template<class T>
T identity(const T& t)
{
return t;
}

template<class T>
class cell
{
public:
//ensure get_value() always work
cell<T>(const T& t=T())
{
set_value(t);
}

cell<T>& operator+=(cell<T>& c)
{
value= boost::bind(operation<std::plus<T> >,
*this,boost::ref(c));
return *this;
}

//make a const version to use when rhs is local
cell<T>& operator+=(const cell<T>& c)
{
value=boost::bind(operation<std::plus<T> >,
*this,c);
return *this;
}

inline T get_value()const{ return value();}

private:
//generic operation on two cell
template<typename Operator >
static T operation(const cell<T>& lhs,const cell<T>& rhs)
{
return Operator()(lhs.get_value(),rhs.get_value());
}

inline cell<T>& set_value(const T& v)
{
value = boost::bind(&identity<T>,v);
return *this;
}

boost::function0<T> value;
};

template<typename T>
cell<T> operator+(const cell<T>& lhs,const cell<T>& rhs)
{
cell<T> ret(lhs);
return ret+=rhs;
}
template<typename T>
cell<T> operator+(const cell<T>& lhs,cell<T>& rhs)
{
cell<T> ret(lhs);
return ret+=rhs;
}

typedef cell<int> icell;

int main()
{
icell a(1);
std::cout<<a.get_value()<<std::endl;
assert(a.get_value()==1);

icell b;
std::cout<<b.get_value()<<std::endl;
assert(b.get_value()==0);

b=3;
std::cout<<b.get_value()<<std::endl;
assert(b.get_value()==3);

icell c = a + b;
std::cout<<c.get_value()<<std::endl;
assert(c.get_value()==4);

b=5;
std::cout<<c.get_value()<<std::endl;
assert(c.get_value()==6);

c+=a;
std::cout<<c.get_value()<<std::endl;
assert(c.get_value()==7);

icell d=c+icell(2);
std::cout<<d.get_value()<<std::endl;
assert(d.get_value()==9);
}


Michael
 
A

alan

Alf P. Steinbach a écrit :


* alan:
I'm creating a sort-of "wrapper" class which (partly) acts like a
variable. Something like:
template<class t>
class cell{
t curval;
public:
/*public for debugging only - will be private in final version*/
inline cell<t>& set_value(t v){ curval = v; return *this;}
inline t get_value(){ return curval;}
/*actual public interface*/
/*assign to this value*/
inline cell<t>& operator=(t v){ return set_value(v);}
};
[snip: answered]
Basically the cell<> class would be like a spreadsheet cell - when I
assign a formula into it, its value will be automatically updated if
any of the cells in the formula are updated.
The way I intend to implement it is, I extend +-*/ and ?: so that if
any cells are in any parameters, they will instead return a new cell
which registers itself to the input cells. Something like:
template<class t>
cell<t>& operator+(cell<t> v1, t v2){
sum_cell<t> *sum = new sum_cell<t>(v2);
sum.register_yourself_to(v1); //when v1 is update()d, sum's update()
method is called
return (cell<t>&) *sum;
}
If there is already some existing library that does (in some form) the
above, please inform me. I suspect there already is, somehow I have a
feeling I've seen it before.
Perhaps look at the Open Office source?

It is straightforward to use boost::function0<T>(), boost::ref() and
boost::bind() to compose your elements.
Wow. Thanks. I guess I gotta study the boost libraries.
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#include <iostream>
#include <functional>
#include <cassert>

//use with boost::function0<T> to return constant value
template<class T>
T identity(const T& t)
{
return t;

}

template<class T>
class cell
{
public:
//ensure get_value() always work
cell<T>(const T& t=T())
{
set_value(t);
}

cell<T>& operator+=(cell<T>& c)
{
value= boost::bind(operation<std::plus<T> >,
*this,boost::ref(c));
return *this;
}

//make a const version to use when rhs is local
cell<T>& operator+=(const cell<T>& c)
{
value=boost::bind(operation<std::plus<T> >,
*this,c);
return *this;
}

inline T get_value()const{ return value();}
I suppose the above call can be turned into:
inline operator T ()const{ return value();}
private:
//generic operation on two cell
template<typename Operator >
static T operation(const cell<T>& lhs,const cell<T>& rhs)
{
return Operator()(lhs.get_value(),rhs.get_value());
}

inline cell<T>& set_value(const T& v)
{
value = boost::bind(&identity<T>,v);
return *this;
}

boost::function0<T> value;

};

template<typename T>
cell<T> operator+(const cell<T>& lhs,const cell<T>& rhs)
{
cell<T> ret(lhs);
return ret+=rhs;}

template<typename T>
cell<T> operator+(const cell<T>& lhs,cell<T>& rhs)
{
cell<T> ret(lhs);
return ret+=rhs;

}

typedef cell<int> icell;

int main()
{
icell a(1);
std::cout<<a.get_value()<<std::endl;
assert(a.get_value()==1);

icell b;
std::cout<<b.get_value()<<std::endl;
assert(b.get_value()==0);

b=3;
std::cout<<b.get_value()<<std::endl;
assert(b.get_value()==3);

icell c = a + b;
std::cout<<c.get_value()<<std::endl;
assert(c.get_value()==4);

b=5;
std::cout<<c.get_value()<<std::endl;
assert(c.get_value()==6);

c+=a;
std::cout<<c.get_value()<<std::endl;
assert(c.get_value()==7);

icell d=c+icell(2);
std::cout<<d.get_value()<<std::endl;
assert(d.get_value()==9);

}

From a basic analysis (correct me if I'm wrong) it seems that the
value is computed only when referenced (and is recomputed each time
it's referenced). Is this correct?

Dang, and I was going to implement some crazy updating code for
this...

Anyway I recently learned that ?: can't be overloaded, so I'll have to
do some other crazy things in order to handle conditionals. If ! can
be overloaded like the above (such that !!(foo) returns either 1 or 0,
regardless if foo is 0, 1, 42, or 1838596) possibly I can simply
create a function like so:
template<class T>
cell<T> num_if(cell<T> c, cell<T> t, cell<T> e){
return !!(c) * t + !(c) * e;
}

Of course a better approach would be to create a new class based on
the cell class, I suppose.
 
M

Michael DOUBEZ

alan a écrit :
Alf P. Steinbach a écrit :


* alan:
I'm creating a sort-of "wrapper" class which (partly) acts like a
variable. Something like:
template<class t>
class cell{
t curval;
public:
/*public for debugging only - will be private in final version*/
inline cell<t>& set_value(t v){ curval = v; return *this;}
inline t get_value(){ return curval;}
/*actual public interface*/
/*assign to this value*/
inline cell<t>& operator=(t v){ return set_value(v);}
};
[snip: answered]
Basically the cell<> class would be like a spreadsheet cell - when I
assign a formula into it, its value will be automatically updated if
any of the cells in the formula are updated.
The way I intend to implement it is, I extend +-*/ and ?: so that if
any cells are in any parameters, they will instead return a new cell
which registers itself to the input cells. Something like:
template<class t>
cell<t>& operator+(cell<t> v1, t v2){
sum_cell<t> *sum = new sum_cell<t>(v2);
sum.register_yourself_to(v1); //when v1 is update()d, sum's update()
method is called
return (cell<t>&) *sum;
}
If there is already some existing library that does (in some form) the
above, please inform me. I suspect there already is, somehow I have a
feeling I've seen it before.
Perhaps look at the Open Office source?
It is straightforward to use boost::function0<T>(), boost::ref() and
boost::bind() to compose your elements.
Wow. Thanks. I guess I gotta study the boost libraries.

I just used boost::function because it was convenient. If you want
something more evolved, you should look toward counted body idioms and
composite pattern but the principle is the same as here.

I suppose the above call can be turned into:
inline operator T ()const{ return value();}
Yes.

value is computed only when referenced (and is recomputed each time
it's referenced). Is this correct?

The value is computed only when deferenced.
There are some issue in the code I gave with consts being copied rather
than referenced. This would be solved with a counted body + composite
implementation that I mentionned.

A quick hack would be to use shared_ptr said:
Dang, and I was going to implement some crazy updating code for
this...

Anyway I recently learned that ?: can't be overloaded, so I'll have to
do some other crazy things in order to handle conditionals. If ! can
be overloaded like the above (such that !!(foo) returns either 1 or 0,
regardless if foo is 0, 1, 42, or 1838596) possibly I can simply
create a function like so:
template<class T>
cell<T> num_if(cell<T> c, cell<T> t, cell<T> e){
return !!(c) * t + !(c) * e;
}

I don't understand your funtion. You want to do a lazy selector of cell ?

This the implmentation I gave:

template<typename B,class T>
cell<T>& selector(B& b, cell<T>& if_true, cell<T>& if_false)
{
return b?if_true:if_false;
}

And then
template<typename B,class T>
cell<T> select(B& b, cell<T>& if_true, cell<T>& if_false)
{
//suposing cell has a constructor from function0<T>
return cell<T>(boost::bind(selector<B,T>,
boost::ref(b),
boost::ref(if_true),
boost::ref(if_false)));
}

Of course, you would have to provide the same with different
cv-qualifier or use some Boost MPL.

Excuse me for being annal, but you should definitely reimplement it with
counted body + composition rather than boost::function.

Michael
 
A

alan

Hmm. I'm not 100% sure of its effects though, especially since I also
want to do lazy evaluation of something like:
cell said:
The value is computed only when deferenced.
There are some issue in the code I gave with consts being copied rather
than referenced. This would be solved with a counted body + composite
implementation that I mentionned.

A quick hack would be to use shared_ptr<function0<T> > instead.





I don't understand your funtion. You want to do a lazy selector of cell ?
Yes, lazy selector.
This the implmentation I gave:

template<typename B,class T>
cell<T>& selector(B& b, cell<T>& if_true, cell<T>& if_false)
{
return b?if_true:if_false;

}

And then
template<typename B,class T>
cell<T> select(B& b, cell<T>& if_true, cell<T>& if_false)
{
//suposing cell has a constructor from function0<T>
return cell<T>(boost::bind(selector<B,T>,
boost::ref(b),
boost::ref(if_true),
boost::ref(if_false)));

}
.....Mmm, suppose B is itself is a cell?
Basically I might do something like:
cell<bool> some_flag;
cell<int> value1, value2;
cell<int> result;

int
main(void){
result = select( some_flag, value1, value2);
value1 = 42;
value2 = 64;
some_flag = TRUE;
assert(result == value1);
some_flag = FALSE;
assert(result == value2);
}
From a basic analysis of your sample code, yes, I think it does what I
want, but I haven't quite grasped the significance of ref. Binding
yes, ref no.
The constructor with function0<> would I think approximately be
something like:
//in class body
cell<T>(const boost::function0<T> t): value(t) {}

Also I would like to be able to do something like:
result = value1 + 42;
without having to explicitly put the 42 in another cell. I'm
currently trying to hack this through your code but I haven't
succeeded so far. I suppose I need to create a different method other
than operation (maybe operation1) which will only do .get_value() on
the lhs. And maybe another method too which would do .get_Value() on
the rhs only...


Of course, you would have to provide the same with different
cv-qualifier or use some Boost MPL.
Sorry, lost me there. Must be some weird C++ topic I have to study.
Excuse me for being annal, but you should definitely reimplement it with
counted body + composition rather than boost::function.
Sorry, lost me there. Must be some weird C++ topic I have to study
too.
 
M

Michael DOUBEZ

alan a écrit :
Hmm. I'm not 100% sure of its effects though, especially since I also
want to do lazy evaluation of something like:
cell<int> v = other + 42;

The whole point of using boost::function is to provide lazy evaluation.
Yes, lazy selector.

....Mmm, suppose B is itself is a cell?

It can be anything you want provided it can evaluate to bool.
Basically I might do something like:
cell<bool> some_flag;
cell<int> value1, value2;
cell<int> result;

int
main(void){
result = select( some_flag, value1, value2);
value1 = 42;
value2 = 64;
some_flag = TRUE;
assert(result == value1);
some_flag = FALSE;
assert(result == value2);
}

Yes. That would do it.
want, but I haven't quite grasped the significance of ref. Binding
yes, ref no.

If you don't ue ref(), bind will keep a copy of the parameters provided.
If you use ref, it will be a ref_wrapper that will be stored.

Practically:
cell<int> a(1);
cell<int> b(2);

//here, it is a copy of a and b that is kept
function0< cell<int> > c=bind(std::plus< cell<int> >, a,b);

//here, it is a copy of b that is kept but a ref of a
function0< cell<int> > d=bind(std::plus< cell<int> >, ref(a),b);

assert( c.get_value() == 3);
assert( d.get_value() == 3);

a=cell<int>(2);
assert( c.get_value() == 3);//old value of a is kept
assert( d.get_value() == 4);//new value of a is used
The constructor with function0<> would I think approximately be
something like:
//in class body
cell<T>(const boost::function0<T> t): value(t) {}

Also I would like to be able to do something like:
result = value1 + 42;
without having to explicitly put the 42 in another cell. I'm
currently trying to hack this through your code but I haven't
succeeded so far.

You can overload the operators
template<class T>
cell<T>& operator+(cell<T>& lhs,const T& rhs)
{
return lhs+cell<T>(rhs);
}
template<class T>
cell<T>& operator+(const cell<T>& lhs,const T& rhs)
{
return lhs+cell<T>(rhs);
}

Sorry, lost me there. Must be some weird C++ topic I have to study.

A problem arise with local instances of cell<T>.
Since their lifetime is limited by the scope, you cannot use a reference
to them and you must use a copy (i.e. not use ref).

I made a quick hack that consisted in overloading function with const
specifier to identify parameters that were local and thus copy them.
Sorry, lost me there. Must be some weird C++ topic I have to study too

They are patterns. In your problem, the counted body free you from
managing the lifetime of the parameters:
- if they are locals, the content will survive the destruction of the
local
- otherwise, the change in the parameter cell will propagate to cells
using it.

The composite pattern allow you to express an object as a composition of
object. That's what we do with boost::bind(): get_value() will call a
function with parameters that can themselves be the result of a call to
a function and so on.

Retaking the implementation I gave:

//implement here detail of body composite
namespace imp
{
//interface of cell body
template<class T>
struct cell_body
{
virtual ~cell_body(){}
virtual T get_value()const=0;
};

tyedef boost::shared_ptr<cell_body> cell_body_ptr;

//counted cell body storing value
template<class T>
struct cell_body_value: public cell_body
{
cell_body_value(const T& t=T()):t_(t){}
T get_value()const{return t_;}
private:
T t_;
};

//cell body of lazy evaluation of binary operator
template<class T,class BinaryOperator>
struct cell_body_op: public cell_body
{
cell_body_op( cell_body_ptr lhs,
cell_body_ptr rhs,
const BinaryOperator& op=BinaryOperator()):
lhs_(lhs),
rhs_(rhs),
op_(op){}
virtual T get_value(){return op(lhs->get_value(),rhs->get_value();}
private:
cell_body_ptr lhs_;
cell_body_ptr rhs_;
BinaryOperator op_;
};

//do the same for unary operator, ...
};

template<class T>
class cell
{
public:
//ensure get_value() always work
cell<T>(const T& t=T())
{
value_=new imp::cell_body_value(t);
}

//make a const version to use when rhs is local
cell<T>& operator+=(const cell<T>& c)
{
value_=new imp::cell_body_op(value_,c.value_,std::plus());
}

inline T get_value()const{ return value_->get_value();}

private:
imp::cell_body_ptr value_;
};

The code is not tested but should be close.

Michael
 
A

alan

alan a écrit :


The whole point of using boost::function is to provide lazy evaluation.






It can be anything you want provided it can evaluate to bool.



Yes. That would do it.


If you don't ue ref(), bind will keep a copy of the parameters provided.
If you use ref, it will be a ref_wrapper that will be stored.

Practically:
cell<int> a(1);
cell<int> b(2);

//here, it is a copy of a and b that is kept
function0< cell<int> > c=bind(std::plus< cell<int> >, a,b);

//here, it is a copy of b that is kept but a ref of a
function0< cell<int> > d=bind(std::plus< cell<int> >, ref(a),b);

assert( c.get_value() == 3);
assert( d.get_value() == 3);

a=cell<int>(2);
assert( c.get_value() == 3);//old value of a is kept
assert( d.get_value() == 4);//new value of a is used



You can overload the operators
template<class T>
cell<T>& operator+(cell<T>& lhs,const T& rhs)
{
return lhs+cell<T>(rhs);}

template<class T>
cell<T>& operator+(const cell<T>& lhs,const T& rhs)
{
return lhs+cell<T>(rhs);

}
Hmm. Just a question on how C++ handles the dealloc - when is the
object created in cell<T>(rhs) above destroyed?
I was doing something like this:
template<class T>
cell<T>& operator+(cell<T>& lhs, T& rhs)
{
cell<T> ret(lhs);
cell<T> rhsT(rhs);
return ret+=rhsT;
}
However the above would cause a segfault.
A problem arise with local instances of cell<T>.
Since their lifetime is limited by the scope, you cannot use a reference
to them and you must use a copy (i.e. not use ref).

I made a quick hack that consisted in overloading function with const
specifier to identify parameters that were local and thus copy them.
Hmm. From my understanding way back from C, const in an argument
means that the function promises not to modify the data pointed to by
a pointer argument. I don't quite understand how it filters out
local.
They are patterns. In your problem, the counted body free you from
managing the lifetime of the parameters:
- if they are locals, the content will survive the destruction of the
local
- otherwise, the change in the parameter cell will propagate to cells
using it.

The composite pattern allow you to express an object as a composition of
object. That's what we do with boost::bind(): get_value() will call a
function with parameters that can themselves be the result of a call to
a function and so on.

Retaking the implementation I gave:

//implement here detail of body composite
namespace imp
{
//interface of cell body
template<class T>
struct cell_body
{
virtual ~cell_body(){}
virtual T get_value()const=0;

};

tyedef boost::shared_ptr<cell_body> cell_body_ptr;
I read the boost Smart Pointer manuals a bit, and it seems that it is
this which handles reference counting - all reference counting -
without actually having to modify (?) the classes to be reference
counted. Wow. I really have to read how this is implemented.
//counted cell body storing value
template<class T>
struct cell_body_value: public cell_body
{
cell_body_value(const T& t=T()):t_(t){}
T get_value()const{return t_;}
private:
T t_;
};

//cell body of lazy evaluation of binary operator
template<class T,class BinaryOperator>
struct cell_body_op: public cell_body
{
cell_body_op( cell_body_ptr lhs,
cell_body_ptr rhs,
const BinaryOperator& op=BinaryOperator()):
lhs_(lhs),
rhs_(rhs),
op_(op){}
virtual T get_value(){return op(lhs->get_value(),rhs->get_value();}
private:
cell_body_ptr lhs_;
cell_body_ptr rhs_;
BinaryOperator op_;
};

//do the same for unary operator, ...

};

template<class T>
class cell
{
public:
//ensure get_value() always work
cell<T>(const T& t=T())
{
value_=new imp::cell_body_value(t);
}

//make a const version to use when rhs is local
cell<T>& operator+=(const cell<T>& c)
{
value_=new imp::cell_body_op(value_,c.value_,std::plus());
}

inline T get_value()const{ return value_->get_value();}

private:
imp::cell_body_ptr value_;

};

The code is not tested but should be close.
Thanks! It does seem to be what I want (haven't tested myself yet
though).

Sincerely,
AmkG
 
A

alan

//implement here detail of body composite
namespace imp
{
//interface of cell body
template<class T>
struct cell_body
{
virtual ~cell_body(){}
virtual T get_value()const=0;

};

tyedef boost::shared_ptr<cell_body> cell_body_ptr;

//counted cell body storing value
template<class T>
struct cell_body_value: public cell_body
{
cell_body_value(const T& t=T()):t_(t){}
T get_value()const{return t_;}
private:
T t_;
};

//cell body of lazy evaluation of binary operator
template<class T,class BinaryOperator>
struct cell_body_op: public cell_body
{
cell_body_op( cell_body_ptr lhs,
cell_body_ptr rhs,
const BinaryOperator& op=BinaryOperator()):
lhs_(lhs),
rhs_(rhs),
op_(op){}
virtual T get_value(){return op(lhs->get_value(),rhs->get_value();}
private:
cell_body_ptr lhs_;
cell_body_ptr rhs_;
BinaryOperator op_;
};

//do the same for unary operator, ...

};

template<class T>
class cell
{
public:
//ensure get_value() always work
cell<T>(const T& t=T())
{
value_=new imp::cell_body_value(t);
}

//make a const version to use when rhs is local
cell<T>& operator+=(const cell<T>& c)
{
value_=new imp::cell_body_op(value_,c.value_,std::plus());
}

inline T get_value()const{ return value_->get_value();}

private:
imp::cell_body_ptr value_;

};

The code is not tested but should be close.
It didn't compile but I tried hacking through it to make it compile.
I've managed to make it compile but now it won't run ^^;

Here's what I hacked up:
//I removed the namespace imp thing for now, since
//I was getting rather confused at some point
//implement here detail of body composite
//interface of cell body
template<class T>
class cell_body
{
public:
virtual ~cell_body(){}
virtual T get_value()const{return T();};
};

//The compiler rejected the typedef (because the
//cell_body didn't have a template instantiation)
//so I removed it and instantiated the typedef in
//the classes.

//counted cell body storing value
template<class T>
class cell_body_value: public cell_body<T>
{
public:
cell_body_value(const T& t=T()):t_(t){}
T get_value()const{return t_;}
private:
T t_;
};

//cell body of lazy evaluation of binary operator
template<class T,class BinaryOperator>
class cell_body_op: public cell_body<T> //Added the <T>
{
typedef boost::shared_ptr<cell_body<T> > cell_body_ptr; //Added the
<T>
public:
cell_body_op( cell_body_ptr lhs,
cell_body_ptr rhs,
const BinaryOperator& op=BinaryOperator()):
lhs_(lhs),
rhs_(rhs),
op_(op){}
//minor typos (missing const and _)
virtual T get_value() const {return op_(lhs_->get_value(),rhs_-
get_value());}
private:
cell_body_ptr lhs_;
cell_body_ptr rhs_;
BinaryOperator op_;
};

template<class T>
class cell
{
//instantiated the typedef again.
typedef boost::shared_ptr<cell_body<T> > cell_body_ptr;
public:
//ensure get_value() always work
cell<T>(const T& t=T())
{
//The compiler rejected the direct assignment to value_
//so I did this.
cell_body_ptr tmp(new cell_body_value<T>(t)); //Added the
<T>
value_=tmp;
}

//make a const version to use when rhs is local
//I think this is the function that crashes
cell<T>& operator+=(const cell<T>& c)
{
//The compiler rejected the direct assignment to value_
cell_body_ptr tmp(new cell_body_op said:
(value_, c.value_, std::plus<T>()));
value_=tmp;
}

inline T get_value()const{ return value_->get_value();}

private:
cell_body_ptr value_;

};

I retained the old operator+ definitions.
This works:
cell<int> v;
v = 1;
cout << v.get_value();
This crashes:
cell<int> v, v2;
v = v2 + 1;
cout << v.get_value();

This leads me to suspect that I did something very wrong in the +=
code, possibly in using std::plus<T> in the template instantiation
 
M

Michael DOUBEZ

alan a écrit :
Hmm. Just a question on how C++ handles the dealloc - when is the
object created in cell<T>(rhs) above destroyed?
I was doing something like this:
template<class T>
cell<T>& operator+(cell<T>& lhs, T& rhs)
{
cell<T> ret(lhs);
cell<T> rhsT(rhs);
return ret+=rhsT;
}
However the above would cause a segfault.

Yes, drop the return by reference and return by value; I had started
writing operator+= and changed to operator+ but forgot to change the
return value.
I have not actually compiled and tested the code.

I read the boost Smart Pointer manuals a bit, and it seems that it is
this which handles reference counting - all reference counting -
without actually having to modify (?) the classes to be reference
counted. Wow. I really have to read how this is implemented.

I used smart_ptr for simplicity. In your case, I guess an intrusive_ptr
would be more fitting since you don't need weak_ptr and the additionnal
overhead of external counter and it matches the semantic you intend
(cell should be aware they are referenced).

Michael
 
A

alan

alan a écrit :




Yes, drop the return by reference and return by value; I had started
writing operator+= and changed to operator+ but forgot to change the
return value.
I have not actually compiled and tested the code.
It wasn't working, so I tried hacking together my own version:
#include <boost/shared_ptr.hpp>
//Base cell (should probably be called "formula", though
template<class T>
class cell_base{
public:
virtual T get_value(void)=0;
virtual ~cell_base(){};
};

//a "constant" formula, for example if a cell is
//given a value directly. Also to be used
//when we handle constants.
template<class T>
class cell_base_const : public cell_base<T> {
T val;
public:
cell_base_const(T v) : val(v) {}
virtual T get_value(void){
return val;
}
};

//binary operation formula
template<class T, class BinaryOperation>
class cell_op2 : public cell_base<T> {
typedef boost::shared_ptr< cell_base<T> > cell_base_ptr;
cell_base_ptr lhs, rhs;
public:
cell_op2(cell_base<T>& _lhs, cell_base<T>& _rhs) {
cell_base_ptr tmp1(&_lhs);
lhs = tmp1;
cell_base_ptr tmp2(&_rhs);
rhs = tmp2;
}
virtual T get_value(void){
return BinaryOperation()(lhs->get_value(), rhs-
get_value());
}
};

//the real_cell is the cell itself
//we just declare it here so that
//the cell_adaptor can see it.
template<class T> class real_cell;

//Adapts a real_cell to cell_base
//basically it represents a formula
//composed of only a cell.
template<class T>
class cell_adaptor : public cell_base<T>{
real_cell<T>* c;
public:
cell_adaptor(real_cell<T>& c_) {
c = &c_;
};
virtual T get_value(void){
return c->get_value();
}
};

//The actual cell.
template<class T>
class real_cell {
typedef boost::shared_ptr< cell_base<T> > cell_base_ptr;
cell_base_ptr value;
public:
real_cell<T>(const T& v=T()) {
cell_base_ptr tmp(new cell_base_const<T>(v));
value = tmp;
}
real_cell<T>(cell_base<T>& v){
cell_base_ptr tmp(&v);
value = tmp;
}
T get_value(void){
return value->get_value();
}
};

//This is supposed to be just a shared_ptr
//with a wrapper that makes it act as if
//it were the real_cell. The cell class itself is
//not the real_cell, because we want to handle
//the case where a routine creates a local cell
//that ends up being referred to in a global cell:
//cell<int> global1, global2;
//void foo(void){
// cell<int> local;
// local = global1 + 1;
// gobal2 = local;
//}
//The above doesn't work yet, btw.
template<class T>
class cell{
typedef boost::shared_ptr< real_cell<T> > real_cell_ptr;
real_cell_ptr value;
public:
cell<T>(const T& v=T()){
real_cell_ptr tmp(new real_cell<T>(v));
value = tmp;
}
cell<T>& operator=(const T& v){
*value = v;
return *this;
}
cell<T>& operator=(cell_base<T>& v){
*value = v;
return *this;
}
cell<T>& operator=(cell<T>& v){
value = v.get_real_cell();
return *this;
}
real_cell<T>& get_real_cell(void){return *value;};
T get_value(void){return value->get_value();};
};


#define __CELL_MAKE_OPERATOR(op, fun)\
template<class T>\
cell_op2<T, fun<T> >& op (cell_base<T>& lhs, cell_base<T>& rhs){\
return *(new cell_op2<T, fun<T> >(lhs, rhs)); \
} \
\
template<class T> \
cell_op2<T, fun<T> >& op (cell<T>& lhs, cell<T>& rhs){ \
return *(new cell_adaptor<T>(lhs.get_real_cell())) + \
*(new cell_adaptor<T>(rhs.get_real_cell())); \
} \

//Will need to add other cases (adding to constants, adding a cell to
a formula, etc.)

//Add the operators here.
__CELL_MAKE_OPERATOR(operator+, std::plus)


I intended the cell class to be a sort of wrapper for the real_cell
class. My logic was:
1. function creates local cell
1.1 local cell creates a real_cell
2. function assigns formula to local cell
2.1 local cell passes assignment to real_cell
2.2 real_cell copies formula to itself
3. function assigns local cell to global cell
3.1 global cell requests real_cell from the local cell
3.2 global cell changes its shared_ptr to the real_cell it got (+
+reference)
4. function exits and destroys its local variables
4.1 local cell destroys its shared_ptr (--reference)

So the real_cell should survive. However there is either something
wrong with my implementation, my logic, or my understanding of
shared_ptr, because inserting some reporting code in an otherwise-
empty ~real_cell destructor shows it being called after the function
exits.
 
M

Michael DOUBEZ

alan a écrit :
It didn't compile but I tried hacking through it to make it compile.
I've managed to make it compile but now it won't run ^^;

You will get some recursive behavior because the semantic changed and
because you need an additionnal indirection.

I will send you the code to your address.

Michael
 

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,770
Messages
2,569,583
Members
45,072
Latest member
trafficcone

Latest Threads

Top