Re: Defining a cast on a templated class
On Nov 15, 2:50 pm, Michael DOUBEZ <michael.dou...@free.fr> wrote:
alan a =E9crit :
On Nov 15, 5:32 am, Michael DOUBEZ <michael.dou...@free.fr> wrote:
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.
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.
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.
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