Re: Polymorphic Accumulate
helix wrote:
Is it possible to use polymorphic classes as 'accumulators'?
It's certainly possible, using the letter/envelope idiom, but you
may not want to. std::accumulate copies the accumulator a lot,
and copying is an expensive operation with the letter/envelope
idiom. (In addition, since one of the copies ends up modified,
COW doesn't really help much.)
Consider
the situation where I want to accumulate over a vector, but the user
has the option to decide what 'function' is used.
You can pass an additional parameter with the operator to
accumulate. Note that this binary function also gets copied,
but nowhere near as often as the accumulator, so the
letter/envelop idiom is quite doable for it. (And since it is
never modified, COW is also a valid option.)
Hence, I have a Base
class (itself a binary_function) from which two classes are extended
(Add and Subtract)....
Just a note concerning your vocabulary: the accumumator is the
object in which the results are accumulated, not the operation
being done. (The third parameter to std::accumulate, not the
fourth.)
// Virtual base class defining the functor interface
class Base : public binary_function<double, double, double>
{
public:
virtual double operator()(const double& _Left, const double& _Right)
const = 0;
};
You definitly want to add a virtual destructor to this.
// An adder class
class Add : public Base
{
public:
double operator()(const double& _Left, const double& _Right) const
{
return _Left + _Right;
}
};
// A multiplier class
class Subtract : public Base
{
public:
double operator()(const double& _Left, const double& _Right) const
{
return _Left - _Right;
}
};
.... in my code I now want to construct the relevant accumulator
function (held as a smart pointer, e.g. boost::shared_ptr) and then
call run the accumulator:
void main
Just for the record, it's "int main()"
{
vector<double> a(100, 1.0); // build a vector of 1's
vector<double>::iterator p1 = a.begin();
vector<double>::iterator p2 = a.end();
// ... obtain user choice ....
// create accumulator based on user choice
boost::shared_ptr<Base> Accumulator;
switch (userChoice)
{
case ADD:
Accumulator = boost::shared_ptr<Base>(new Subtract);
break;
case SUBTRACT:
Accumulator = boost::shared_ptr<Base>(new Subtract);
break;
}
// accumulate
double result = accumulate(p1, p2, 0.0, Accumulator());
}
Obviously, this won't work, but does anyone out there know of a way of
achieving my aim? To summarise, how can I get accumulate to work with
(a) polymorphic classes, and (b) through a shared_ptr?
Well, the letter/envelope idiom works fine; it can also be used
with a shared pointer instead of a raw pointer, using COW, or,
as is the case here, never deep copying, since all of the member
functions are const. Or just based on what you have here:
template< typename T >
class AbstractOperator
{
public:
virtual ~AbstractOperator() {}
virtual T operator()( T const& lhs, T const& rhs )
const = 0 ;
} ;
template< typename T >
class PolymorphicOperator
{
public:
PolymorphicOperator( AbstractOperator< T > const* operator )
: myOperator( operator )
{
}
T operator()( T const& lhs, T const& rhs ) const
{
return (*myOperator)( lhs, rhs ) ;
}
private:
AbstractOperator< T > const* myOperator ;
} ;
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientie objet/
Beratung in objektorientierter Datenverarbeitung
9 place Simard, 78210 St.-Cyr-l'Icole, France, +33 (0)1 30 23 00 34
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]