mem_fn
overloadsSection: 22.10 [function.objects], 22.10.16 [func.memfn] Status: C++14 Submitter: Jonathan Wakely Opened: 2011-04-18 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [function.objects].
View all issues with C++14 status.
Discussion:
The mem_fn
overloads for member functions are redundant and misleading
and should be removed from the post-C++11 WP.
mem_fn
was specified by
a single signature:
template<class R, class T> unspecified mem_fn(R T::* pm);
and was accompanied by the remark "Implementations may implement mem_fn
as a set of overloaded function templates." This remark predates variadic templates
and was presumably to allow implementations to provide overloads for a limited
number of function parameters, to meet the implementation-defined limit on numbers of
template parameters.
CopyConstructible
concept
(those overloads first appeared in N2322.) The overloads failed to
account for varargs member functions (i.e. those declared with an
ellipsis in the parameter-declaration-clause) e.g.
struct S { int f(int, ...); };
Syntactically such a function would be handled by the original
mem_fn(R T::* pm)
signature, the only minor drawback being that there
would be no CopyConstructible
requirement on the parameter list. (Core
DR 547 clarifies that partial specializations can be written to match
cv-qualified and ref-qualified functions to support the case where R T::*
matches a pointer to member function type.)
mem_fn(R T::* pm)
signature.
Concepts were removed from the draft and N3000 restored the original
single signature and accompanying remark.
LWG 1230 was opened to strike the remark again and to add an overload
for member functions (this overload was unnecessary for syntactic reasons and
insufficient as it didn't handle member functions with cv-qualifiers and/or
ref-qualifiers.)
920 (and 1230) were resolved by restoring a full set of
(non-concept-enabled) overloads for member functions with cv-qualifiers and ref-qualifiers,
but as in the concept-enabled draft there were no overloads for member functions with
an ellipsis in the parameter-declaration-clause. This is what is present in the FDIS.
Following the thread beginning with message c++std-lib-30675, it is my
understanding that all the mem_fn
overloads for member functions are
unnecessary and were only ever added to allow concept requirements.
I'm not aware of any reason implementations cannot implement mem_fn
as
a single function template. Without concepts the overloads are
redundant, and the absence of overloads for varargs functions can be
interpreted to imply that varargs functions are not intended to work
with mem_fn
. Clarifying the intent by adding overloads for varargs
functions would expand the list of 12 redundant overloads to 24, it
would be much simpler to remove the 12 redundant overloads entirely.
[Bloomington, 2011]
Move to Review.
The issue and resolution appear to be correct, but there is some concern that the wording of INVOKE may be different depending on whether you pass a pointer-to-member-data or pointer-to-member-function. That might make the current wording necessary after all, and then we might need to add the missing elipsis overloads.
There was some concern that the Remark confirming implementors had freedom to implement this as a set of overloaded functions may need to be restored if we delete the specification for these overloads.
[2012, Kona]
Moved to Tentatively Ready by the post-Kona issues processing subgroup.
[2012, Portland: applied to WP]
Proposed resolution:
This wording is relative to the FDIS.
Change the <functional>
synopsis 22.10 [function.objects] p. 2 as follows:
namespace std { […] // [func.memfn], member function adaptors: template<class R, class T> unspecified mem_fn(R T::*);template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...)); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) volatile); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const volatile); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) volatile &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const volatile &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) &&); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const &&); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) volatile &&); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const volatile &&);[…] }
Change 22.10.16 [func.memfn] as follows:
template<class R, class T> unspecified mem_fn(R T::*);template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...)); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) volatile); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const volatile); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) volatile &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const volatile &); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) &&); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const &&); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) volatile &&); template<class R, class T, class... Args> unspecified mem_fn(R (T::*)(Args...) const volatile &&);