Many standard library algorithms accept function objects - objects that can
appear to the left of a function call operator - as arguments. However,
pointers to members do not support the function call syntax and cannot be used
directly. Instead, they need to be wrapped with the help of std::mem_fun
,
std::mem_fun_ref
, or tr1::mem_fn
.
This paper proposes an extension to the C++ language that will allow pointers to
member to appear to the left of the function call operator. This will make C++
more regular and enable the more concise and intuitive std::for_each(
v.begin(), v.end(), &Shape::draw )
. In addition, the
specification of two of the components in TR1, tr1::function
and
tr1::bind
, will be simplified by omitting the special handling of
pointers to members. tr1::mem_fn
[N1432]
will become redundant and its implementation - the trivial identity function; a
pointer to member will have the same properties as the function object returned
by tr1::mem_fn
.
Expressing equivalent operations with a uniform syntax is important for generic
code. The standard library algorithms, such as for_each
, can take
advantage of the fact that ordinary function pointers and user-defined function
objects support a common function call operator:
struct X { void f() const; }; void g(X const & x); struct H { void operator()(X const & x) const; }; int main() { std::vector<X> v; std::for_each( v.begin(), v.end(), g ); std::for_each( v.begin(), v.end(), H() ); }
However, calling a member function such as &X::f
requires a
different syntax, and cannot be performed by for_each
directly. A
pointer to a member function needs to be adapted - wrapped in a function object
- first. The standard library supplies mem_fun
and mem_fun_ref
for this purpose:
int main() { std::vector<X> v; std::for_each( v.begin(), v.end(), std::mem_fun_ref(&X::f) ); std::vector<X*> v; std::for_each( v.begin(), v.end(), std::mem_fun(&X::f) ); }
This is unnecessarily verbose. The simple
std::for_each( v.begin(), v.end(), &X::f );
syntax feels more natural and is much easier to teach.
The Library Extensions Technical Report [N1660] contains
an enhanced member pointer adapter, tr1::mem_fn
[1432],
that is more convenient than std::mem_fun
and std::mem_fun_ref
.
Nevertheless, its use is still verbose and can be made redundant by the
extension proposed herein, which is modeled on the proven semantics of tr1::mem_fn
.
As a reflection of the need for simpler and more accessible syntax, two
components of the Technical Report, tr1::function
and tr1::bind
,
treat member pointers exactly as if the proposed extension were already in
place. The specification and implementation of these components would be
considerably simpler in a language where this is already the case, as the
library workarounds implementing the illusion of member pointer callability
could be removed.
Replace the second part of the third sentence in 5.2.2/1 ([expr.call]/1),
or it shall have pointer to function type.
with
or it shall have pointer to function or pointer to member type.
Add a new paragraph after 5.2.2/1 ([expr.call]/1):
In an ordinary function call of the form
pm(a1, ..., aN)
, wherepm
is of type "pointer to member ofT
",T
shall be a completely defined class type andN
shall be 1 whenpm
is a pointer to data member,M+1
whenpm
is a pointer to a member function takingM
arguments. The behavior of the function call whenpm
is a pointer to a member function is equivalent to(a1.*pm)(a2, ..., aN)
, whena1
is of a possibly cv-qualified class type of whichT
is a base class,((*a1).*pm)(a2, ..., aN)
otherwise. The behavior of the function call whenpm
is a pointer to a data member is equivalent toa1.*pm
whena1
is of a possibly cv-qualified class type of whichT
is a base class,(*a1).*pm
otherwise.
Add
in this context.
to the end of footnote 114.
[Note: changes are relative to ISO/IEC 14882:2003(E).]
The proposal is a pure extension.
--end