Boost logo

Boost :

From: Jost, Andrew (Andrew_Jost_at_[hidden])
Date: 2005-07-19 07:45:58


> -----Original Message-----
> From: boost-bounces_at_[hidden]
> [mailto:boost-bounces_at_[hidden]] On Behalf Of Fernando Cacciola
> Sent: Saturday, July 16, 2005 12:48 AM
> To: boost_at_[hidden]
> Subject: Re: [boost] New Library Proposal: dual_state

<clip -- discussion on why ?: is clearer than "adaptor">

> You said that
>
> "the door has been flung open to many templated constructs
> that are more difficlt with the ?: operator. For example, a
> boost::transform_iterator could be created with the adaptor
> to automatically access the underlying objects in a sequence."
>
> I disagree.. can you post a concrete example with a construct
> that is indeed more difficult with operator ?: (... and be
> fair; i.e. code the operator version the right way...)
>
>
> IMO you still need to show that the adpator is indeed a good
> thing; if you do that we can start discussing a proper design
> and implementation for it.
>

Okay, I'll try. How about finding the max_element (or min_element) of a
series of optional integers? Using the ?: operator, we might do this in
two steps, the first to filter out non-existent values, the second to
apply the max_element algorithm. Another way would be to write a custom
predicate function that knows how to compare "full" and "empty"
Boost::Optional objects or that duplicates the functionality of adaptor.

However, by using an adaptor in conjunction with
boost::transform_iterator, the job can be accomplished in one loop
without the difficulty of writing a custom predicate. Here is some
example code (BTW, others seem to prefer the spelling "adaptor," which
is more consistent with other standardized names like "iterator," so
I'll conform to that):

// -- begin
typedef boost::optional<int> opt_int;
typedef std::vector<opt_int> Vec;
typedef Vec::const_iterator cIter;

Vec v;
int max;

v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(boost::none);
v.push_back(3);
v.push_back(4);
v.push_back(boost::none);
v.push_back(5);

// METHOD #1a: copy to a new vector
std::vector<int> tmp;
for( cIter p = v.begin(); p != v.end(); ++p ) {
    if( *p ) tmp.push_back( p->get() );
}
max = *std::max_element( tmp.begin(), tmp.end() );

// METHOD #1b: copy using ?: to provide a signal value for undefined
elements (similar to adaptor)
tmp.clear();
for( cIter p = v.begin(); p != v.end(); ++p ) {
    tmp.push_back( *p ? p->get() : -1 );
}
max = *std::max_element( tmp.begin(), tmp.end() );

// METHOD #2a: define a custom predicate
template< class T, class Pred, T Def = T() >
class optPred : public std::binary_function<boost::optional<T>,
boost::optional<T>, bool> {
    Pred f;
    T _eval( const boost::optional<T>& x ) const {
        return ( x ? x.get() : Def );
    }
public:
    optPred() : f( Pred() ) {}
    bool operator()( const first_argument_type& a, const
second_argument_type& b ) const {
        return f( _eval(a), _eval(b) );
    }
};
opt_int opt_max;
opt_max= *std::max_element( v.begin(), v.end(), optPred< int,
std::less<int>, -1 >() );

// METHOD #2b: use an adaptor-like predicate
template< class T >
class adaptor_substitute : public std::unary_function<
boost::optional<T>, T > {
    T Def;
public:
    _adaptor_() : Def( T() ) {}
    _adaptor_(T def) : Def( def ) {}
    T operator()(const argument_type& x ) {
        return ( x ? x.get() : Def );
    }
};
max = *std::max_element(
    boost::make_transform_iterator( v.begin, adaptor_substitute<int>(-1)
),
    boost::make_transform_iterator( v.end, adaptor_substitute<int>(-1)
)
);

// METHOD #3: use an adaptor
max = *std::max_element(
    boost::make_transform_iterator( v.begin,
boost::optional<int>::adaptor(-1) ), // NOTE:
boost::optional<int>::adaptor does not currently exist
    boost::make_transform_iterator( v.end,
boost::optional<int>::adaptor(-1) )
);

// -- end

It seems to me the adaptor, at the very least, saves us the trouble of
defining a custom predicate. The similar exercise for min_element can
be done by choosing a different signal value, such as 0x7FFFFFFF (the
point at "infinity").

I hope this clears up my comment about using adaptor with
boost::transform_iterator, but let me know if I haven't convinced you.

-Andy


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk