Document number: N1432=03-0014
Programming Language C++, Library Subgroup
 
Peter Dimov <pdimov@mmltd.net>
 
February 28, 2003

A Proposal to Add an Enhanced Member Pointer Adaptor to the Library Technical Report

I. Motivation

The canonical solution for storing polymorphic objects in standard library containers is to use a smart pointer such as shared_ptr [Dimov03a]. Unfortunately, the standard adaptors for pointers to members described in section 20.3.8 do not support smart pointers.

This document proposes an enhanced member pointer adaptor, mem_fn, that

mem_fn supports the familiar idiom for invoking a member function on all container elements:

    std::for_each(v.begin(), v.end(), mem_fn(&Shape::draw));

The statement works for a container that stores objects, pointers, smart pointers, or iterators.

This flexibility allows components that accept function objects as input to offer transparent support for pointers to members by using mem_fn internally to turn the pointer to member into a function object [Dimov03b]. As an example, consider this hypothetical for_each overload:

template<class It, class R, class T> void for_each(It first, It last, R T::* pm)
{
    std::for_each(first, last, mem_fn(pm));
}

Scott Meyers remarks in [Meyers01] that

In a perfect world, I'd also be able to use for_each to invoke Widget::test on each object in vw:

for_each(vw.begin(), vw.end(), &Widget::test);    // Call #2 (won't compile)

In fact, if the world were really perfect, I'd be able to use for_each to invoke Widget::test on a container of Widget* pointers, too:

list<Widget*> lpw; // lpw holds pointers to widgets
for_each(lpw.begin(), lpw.end(), &Widget::test);  // Call #3 (also won't compile)

This is exactly the functionality offered by the above for_each overload.

The hypothetical proposed text for our enhanced for_each can reuse the mem_fn specification as well:

template<class It, class R, class T> void for_each(It first, It last, R T::* pm);

Effects: equivalent to std::for_each(first, last, mem_fn(pm));

II. Impact On the Standard

This proposal is almost a pure library extension. It proposes changes to an existing header, <functional>, but it does not require changes to any standard classes or functions and it does not require changes to any of the standard requirement tables. It does not require any changes in the core language, and it has been implemented in standard C++ [Boost01]. The proposal does not depend on any other library extensions.

III. Design Decisions

A. Separate Function Template vs std::mem_fun Extension

This proposal introduces a new function template mem_fn and does not propose changes to the existing function template std::mem_fun in order to not impact existing code, as the return type of std::mem_fun is specified by the standard.

B. Unified Handling of Pointers and References

The function objects returned by mem_fn can take either an object pointer or an object reference as its first argument. This allows components that automatically recognize pointers to members, transparently wrapping them with mem_fn, to accept pointers and references. As the wrapping is done implicitly, the user has no way to specify one or the other.

C. Unspecified Return Type

The return type of mem_fn is not specified by this proposal, as it is rarely needed, and can reflect implementation details. The Boost implementation does not specify the return type of mem_fn, and there have been no complaints from users.

D. get_pointer(t)->*pm vs ( *t).*pm

When the argument is not an object reference, the Boost implementation uses an unqualified call to get_pointer to obtain a pointer from the argument, and the ->* operator to perform the call. This proposal dereferences the argument instead, using the .* operator for the call. This allows mem_fn to support most smart pointers and iterators "out of the box", without requiring explicit support in the form of a get_pointer overload.

E. result_type for data members

The return type of mem_fn(&X::f), where f is a member function of X, is always the same as the return type of f. The return type of mem_fn(&X::m), where m is a data member of X of type M, can vary depending on M and the cv-qualification of the object identified by the first argument of the call. When M is a reference type, the return type is M; otherwise, the return type is a reference to (possibly cv-qualified) M.

In this proposal, implementations are allowed to define the result_type of the function object returned by mem_fn(&X::m) as either M or M const &. It is not possible to express the exact return type in a single typedef, and neither M nor M const & is inherently a better choice.

IV. Proposed Text

A. Additions to header <functional> synopsis (20.3)

  template<class R, class T> unspecified mem_fn(R T::* pm);

B. mem_fn

mem_fn(&X::f), where f is a member function of X, returns an object through which &X::f can be called given a pointer, a smart pointer, an iterator, or a reference to X followed by the argument list required for X::f, if any. The returned object is CopyConstructible, Assignable, its copy constructor and assignment operator do not throw exceptions, and it has a nested typedef result_type defined as the return type of f.

mem_fn(&X::m), where m is a data member of X, returns an object through which a reference to &X::m can be obtained given a pointer, a smart pointer, an iterator, or a reference to X. The returned object is CopyConstructible, Assignable, its copy constructor and assignment operator do not throw exceptions, and it has a nested typedef result_type defined as either M or M const & where M is the type of m.

      template<class R, class T> unspecified mem_fn(R T::* pm);

Returns:

Throws: nothing.

Notes: Implementations are allowed to impose an upper limit on n. Implementations are allowed to implement mem_fn as a set of overloaded function templates.

V. References

[Boost01] Boost mem_fn library documentation, September 2001. Available online at http://www.boost.org/libs/mem_fn/

[Dimov03a] Peter Dimov, Beman Dawes, Greg Colvin, A Proposal to Add General Purpose Smart Pointers to the Library Technical Report, C++ committee document N1431=03-0013, February 2003. Available online at http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1431.htm

[Dimov03b] Peter Dimov, Douglas Gregor, Jaakko Järvi, Gary Powell, A Proposal to Add an Enhanced Binder to the Library Technical Report, C++ committee document N1438=03-0020, February 2003. Available online at http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1438.htm

[Meyers01] Scott Meyers, Effective STL, Item 41, page 174, Addison-Wesley, June 2001, ISBN 0-201-74962-9.