However, if we instead defined operator() to accept Predicate's
argument_type unmodified, this would be needlessly inefficient if it were a
value type; the argument would be copied twice - once when calling
unary_negate's operator(), and again when
operator() called the adapted function.

So how we want to declare the argument for operator() depends
on whether or not the Predicate's argument_type is a reference. If
it is a reference, we want to declare it simply as argument_type;
if it is a value we want to declare it as
const argument_type&.

The Boost call_traits class
template contains a param_type typedef, which uses partial
specialisation to make precisely this decision. If we were to declare
operator() as

the desired result would be achieved - we would eliminate references to
references without loss of efficiency. In fact, the actual declaration is
slightly more complicated because of the use of function object traits, but
the effect remains the same.

Limitations

Both the function object traits and call traits used to realise these
improvements rely on partial specialisation, these improvements are only
available on compilers that support that feature. With other compilers, the
negators in this library behave very much like those in the Standard -
ptr_fun will be required to adapt functions, and references to
references will not be avoided.