Topic: Inconsistent treatment of function objects in the WP


Author: "Kevin S. Van Horn" <kevin.s.vanhorn@iname.com>
Date: 1997/07/18
Raw View
I'm finding some real problems with the handling of function objects in
the standard library, as described in the Dec. '96 WP.  The problem is
that there is ambiguity and inconsistency in what the argument_type and
result_type typedefs should be.  In particular, if a function object
takes a T const & argument, should argument_type be T or T const &?  It
can work out either way, and this causes problems with composing
function adaptors.  For example, there is an inconsistency between the
declarations for unary_negate and pointer_to_unary_function.  Here are
their declarations and their associated helper functions:

  template <class Predicate>
  class unary_negate
    : public unary_function<Predicate::argument_type,bool> {
  public:
    explicit unary_negate(const Predicate& pred);
    bool operator()(const argument_type& x) const;
  };

  template <class Predicate>
  unary_negate<Predicate> not1(const Predicate& pred);
  // Returns: unary_negate<Predicate>(pred).

  template <class Arg, class Result>
  class pointer_to_unary_function : public unary_function<Arg, Result> {
  public:
    explicit pointer_to_unary_function(Result (*f)(Arg));
    Result operator()(Arg x) const;
  };

  template <class Arg, class Result>
  pointer_to_binary_function<Arg,Result>
  ptr_fun(Result (*f)(Arg1));
  // Returns:  pointer_to_binary_function<Arg,Result>(f).

For unary_negate<T,U>, operator() takes an argument of type T const &,
but for pointer_to_unary_function<T,U>, operator() takes an argument
of type T.  This can cause problems when I try to compose the two.
For example, if I have the function declaration

  int foo(int const & x);

then the expression not1(ptr_fun(&foo)) is not legal!  The problem is
that argument_type for ptr_fun(&foo) is int const &, which means that
unary_negate tries to declare operator() to take an argument of type
  int const & const & !

My suggestion is that argument_type for a function object should
always be the full type of the parameter to operator(), and the same
for result_type, since stripping off "&" and "const" from the type may
throw away useful information.  For example, unary_negate would be
declared as

  template <class Predicate>
  class unary_negate
    : public unary_function<Predicate::argument_type,bool> {
  public:
    explicit unary_negate(const Predicate& pred);
    bool operator()(argument_type x) const;
    // Note: *not* argument_type const & x !
  };

and logical_not would be declared as

  template <class T>
  struct logical_not
    : unary_function<T const &, bool> {
    //               ^^^^^^^^^ *not* just T!
    bool operator()(T const & x) const;
  };

If you then want to get at the underlying value type, you still can --
it's type_traits<argument_type>::value_type, where type_traits is
defined as follows:

template <class T>
struct type_traits {
  typedef T                  value_type;
  typedef value_type &       mutable_reference;
  typedef value_type const & const_reference;
  typedef mutable_reference  reference;
  typedef value_type *       mutable_pointer;
  typedef value_type const * const_pointer;
  typedef mutable_pointer    pointer;
};

template <class T>
struct type_traits<T const> {
  typedef type_traits<T>::value_type value_type;
  typedef value_type &       mutable_reference;
  typedef value_type const & const_reference;
  typedef const_reference    reference;
  typedef value_type *       mutable_pointer;
  typedef value_type const * const_pointer;
  typedef const_pointer      pointer;
};

template <class T>
struct type_traits<T &> {
  typedef type_traits<T>::value_type value_type;
  typedef value_type &       mutable_reference;
  typedef value_type const & const_reference;
  typedef type_traits<T>::reference reference;
  typedef value_type *       mutable_pointer;
  typedef value_type const * const_pointer;
  typedef type_traits<T>::pointer pointer;
};

------------------------------------------------------------------
Kevin S. Van Horn            | kevin.s.vanhorn@iname.com
KSVH Software and Consulting | http://www.xmission.com/~ksvhsoft/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]