| Home | Libraries | People | FAQ | More

# Member Function Adapters

The header functional.hpp includes improved versions of the full range of member function adapters from the the C++ Standard Library (§20.3.8):

- `mem_fun_t`
- `mem_fun1_t`
- `const_mem_fun_t`
- `const_mem_fun1_t`
- `mem_fun_ref_t`
- `mem_fun1_ref_t`
- `const_mem_fun_ref_t`
- `const_mem_fun1_ref_t`

as well as the corresponding overloaded helper functions

- `mem_fun`
- `mem_fun_ref`

The following changes have been made to the adapters as specified in the Standard:

- The `first_argument_type` typedef has been corrected for the `const_` family of member function adapters (see below).
- The argument passed to `mem_fun1_t` and its variants is passed using the `call_traits::param_type` for the member function's argument type.

### first_argument_type

The standard specifies `const_mem_fun1_t`, for example, like this:

>     template <class S, class T, class A> class const_mem_fun1_t
>       : public binary_function<T*, A, S> {
>     public:
>       explicit const_mem_fun1_t(S (T::*p)(A) const);
>       S operator()(const T* p, A x) const;
>     };

Note that the first argument to `binary_function` is `T*` despite the fact that the first argument to `operator()` is actually of type `const T*`.

Does this matter? Well, consider what happens when we write

>     struct Foo { void bar(int) const; };
>     const Foo *cp = new Foo;
>     std::bind1st(std::mem_fun(&Foo::bar), cp);

We have created a `const_mem_fun1_t` object which will effectively contain the following

>     typedef Foo* first_argument_type;

The `bind1st` will then create a `binder1st` object that will use this `typedef` as the type of a member which will be initialised with `cp`. In other words, we will need to initialise a `Foo*` member with a `const Foo*` pointer! Clearly this is not possible, so to implement this your Standard Library vendor will have had to cast away the constness of `cp`, probably within the body of `bind1st`.

This hack will not suffice with the improved binders in this library, so we have had to provide corrected versions of the member function adapters as well.

### Argument Types

The standard defines `mem_fun1_t`, for example, like this (§20.3.8 ¶2):

>     template <class S, class T, class A> class mem_fun1_t
>       : public binary_function<T*, A, S> {
>     public:
>       explicit mem_fun1_t(S (T::*p)(A));
>       S operator()(T* p, A x) const;
>     };

Note that the second argument to `operator()` is exactly the same type as the argument to the member function. If this is a value type, the argument will be passed by value and copied twice.

However, if we were to try and eliminate this inefficiency by instead declaring the argument as `const A&`, then if A were a reference type, we would have a reference to a reference, which is currently illegal (but see C++ core language issue number 106)

So the way in which we want to declare the second argument for `operator()` depends on whether or not the member function's argument is a reference. If it is a reference, we want to declare it simply as `A`; if it is a value we want to declare it as `const A&`.

The Boost call_traits class template contains a `param_type` typedef, which uses partial specialisation to make precisely this decision. By declaring the `operator()` as

>     S operator()(T* p, typename call_traits<A>::param_type x) const

we achieve the desired result - we improve efficiency without generating references to references.

### Limitations

The call traits template used to realise some improvements relies on partial specialisation, so these improvements are only available on compilers that support that feature. With other compilers, the argument passed to the member function (in the `mem_fun1_t` family) will always be passed by reference, thus generating the possibility of references to references.

Revised 02 December, 2006

Copyright © 2000 Cadenza New Zealand Ltd.

Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)