Topic: Extensions to STL's function objects and adaptors
Author: "Kevin S. Van Horn" <ksvhsoft@xmission.com>
Date: 1997/08/21 Raw View
I've written what I consider to be an improved version of the draft C++
standard library header <functional>. (This is the one that contains
the various STL function object classes and function object adaptors.)
You can find it on my website (http://www.xmission.com/~ksvhsoft/) as
part of the collection of C++ software components I am making available
for free.
I would appreciate any comments people might have on it.
The biggest change I have made has to do with the typedefs for argument
and result types. In the current draft standard it is not made clear,
in general, whether these should be the complete types (e.g., foo const
& for an argument type) or the plain, unelaborated types on which the
complete types are based (foo in the preceding example.) In the current
<functional> header it can go either way. For example, the class
negate<int> declares operator() as
int operator()(int const & x) const
with negate<int>::argument_type defined as int (the "plain" type)
instead of int const & (the full argument type). But if I have a
function f declared as
foo f(foo const & x);
then the type of ptr_fun(f) is
pointer_to_unary_function<foo const &, foo>,
which defines argument_type to be foo const & (the complete type)
instead of foo (the "plain" type) -- just the opposite of negate<int>!
My approach to handling this problem is to have separate typedefs for
the plain and complete argument/result types. Thus, unary function
objects have typedefs for the following:
argument_type (plain argument type)
xargument_type (full argument type)
result_type (plain result type)
xresult_type (full result type).
The type arguments to the unary_function and binary_function templates
are understood to be the complete types (xresult_type, etc.), and the
"plain" types are deduced from these.
The next most important change I've made is to remove the need for the
pointer_to_unary_funnction and pointer_to_binary_function class
templates, and the ptr_fun convenience function. Instead, I borrow a
trick from the <iterator> header. That header uses an iterator_traits<>
class template to access the types associated with an iterator type.
iterator_traits<> can be thought of as a "type function" -- it takes an
iterator type as input, and outputs a traits class which has typedefs
for the value_type, difference_type, etc. associated with the iterator
type.
In the same vein, I define the class templates fct0_traits<>,
fct1_traits<>, and fct2_traits<>. Each of these takes a function type,
function pointer type, or function object type as argument, and returns
a traits class that has typedefs for xresult_type, result_type, etc.
The numbers 0, 1, and 2 refer to nullary, unary, and binary functions.
Finally, I've fixed what appear to be some oversights or typos in the
December '96 WP regarding the class templates mem_fun_t, mem_fun1_t,
mem_fun_ref_t, and mem_fun1_ref_t, and associated convenience functions.
The WP didn't declare operator() to be const for these class templates,
for no good reason I can discern; since all other function object
classes declare operator() to be const, I have done the same with these.
More significantly, I have introduced const- and/or volatile-qualified
specializations of these class templates, with appropriately modified
argument types for operator(). For example, let C be a class type (no
qualifiers, not a reference type), and R an arbitrary type; then
1. mem_fun_t<R, C> declares operator() as
R operator()(C * p) const
and its ctor takes an argument of type
R (C::*)().
2. mem_fun_t<R, C const> declares operator() as
R operator()(C const * p) const.
and its ctor takes an argument of type
R (C::*)() const
[my extension].
3. xmem_fun_t<R, C volatile> declares operator() as
R operator()(C volatile * p)
and its ctor takes an argument of type
R (C::*)() volatile
[my extension].
I've defined mem_fun_t<R, C const volatile> similarly, and used the same
scheme with mem_fun1_t, mem_fun_ref_t, and mem_fun1_ref_t. I've also
defined the function templates mem_fun, mem_fun1, mem_fun_ref, and
mem_fun1_ref to look at whether the member function pointer passed is
const- and/or volatile-qualified, and reflect these in the return type.
I would appreciate it if anyone interested in these issues would take a
look at what I've written, and give me their comments. To find it, go
to my web site (given below), follow the software components link, then
follow the "Function Objects" link.
-----------------------------------------------------------------
Kevin S. Van Horn | ksvhsoft@xmission.com
KSVH Software and Consulting | http://www.xmission.com/~ksvhsoft/
---------
Administrivia: genstl-request@graphics.stanford.edu
Mailing list: genstl@graphics.stanford.edu
Archive: ftp://ftp-graphics.stanford.edu/pub/genstl-archive/
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
[ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]