Boost logo

Boost :

Subject: Re: [boost] [Review:Algorithms] Order of args to clamp
From: Jeffrey Lee Hellrung, Jr. (jeffrey.hellrung_at_[hidden])
Date: 2011-09-23 20:12:51


On Fri, Sep 23, 2011 at 4:04 PM, Marshall Clow <mclow.lists_at_[hidden]>wrote:

> On Sep 23, 2011, at 12:01 PM, Jeffrey Lee Hellrung, Jr. wrote:
>
> > On Fri, Sep 23, 2011 at 9:34 AM, Marshall Clow <mclow.lists_at_[hidden]
> >wrote:
> >
> >>
> >> On Sep 23, 2011, at 9:21 AM, Phil Endecott wrote:
> >>
> >>> Dear All,
> >>>
> >>> Some quick comments about the proposed clamp() function:
> >>
> > [...]
> >
> >>> Like min & max, clamp has a single type template parameter; what are
> the
> >> implications of this? For example, if I pass a mixture of std::string
> and
> >> const char* arguments, what will happen? Ideally, (a) all combinations
> would
> >> compile, and (b) conversions from const char* to std::string will only
> >> happen when necessary, not unconditionally for all of the arguments.
> (Maybe
> >> that is asking too much, though.)
> >>
> >> Dunno; I'll put it on the list of things to think about.
> >>
> > Isn't this *precisely* why we have common_type now? :)
> >
> > I haven't actually looked at the documentation, but I'm gathering that
> > std::less<T> is the default comparison function object, in which case I
> > would suggest this should be replaced with some other function object
> with a
> > templated operator() that wraps operator<; this should avoid unnecessary
> > temporaries in more cases.
>
>
> Are you talking about something like this? (typed w/o benefit of compiler)
>
> namespace boost { struct less
> {
> typedef bool result_type;
>
> template <typename T> // T models Regular
> bool operator()(const T& x, const T& y) const { return std::less<T>()(x,
> y); }
>
> template <typename T, typename U>
> bool operator ()(const T& x, const U&y) const { return
> std::less<boost::common_type<T, U>() ( x, y )); }
> };
> }
>

Hmmm...more like (likewise w/o compiling)

template< class T, class L, class U >
typename common_type< T const &, L const &, U const & >::type
clamp(T const & x, L const & lower, U const & upper)
{ return x < lower ? lower : upper < x ? upper : x; }

for the use of common_type (assuming it accepts 3 parameters, which I seem
to remember it did; if not, just nest); and something like

struct less
{
    typedef bool result_type;
    template< class T, class U >
    bool operator()(T const & x, U const & y) const
    { return x < y; }
};

for the default comparison function object. I don't think using std::less,
directly or indirectly, over operator< buys you anything here, does it?

While we're on the topic of clamping, I can see where an in-place clamping
function would be desirable. Something like

template< class T, class L, class U >
void
clamp_ip(T& x, L const & lower, U const & upper) // ip == "in-place"
{
    if(x < lower)
        x = lower;
    else if(upper < x)
        x = upper;
}

Could optionally return a T& instead of void, a la operator=. It makes x =
clamp(x, lower, upper), which I would consider a common use case, less
onerous when x is a long'ish identifier. The in-place clamp also has an
outside of chance of being more efficient, as it could require few
conversions. Thoughts?

- Jeff


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