This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Resolved status.
Section: 22.10 [function.objects] Status: Resolved Submitter: Daniel Krügler Opened: 2009-12-14 Last modified: 2017-03-21
Priority: Not Prioritized
View all other issues in [function.objects].
View all issues with Resolved status.
Discussion:
This issue is a follow-up of the discussion on issue 870 during the 2009 Santa Cruz meeting.
The class templates unary_function and binary_function are actually very simple typedef providers,
namespace std { template <class Arg, class Result> struct unary_function { typedef Arg argument_type; typedef Result result_type; }; template <class Arg1, class Arg2, class Result> struct binary_function { typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Result result_type; }; }
which may be used as base classes (similarly to the iterator template), but were originally not intended as a customization point. The SGI documentation introduced the concept Adaptable Unary Function as function objects "with nested typedefs that define its argument type and result type" and a similar definition for Adaptable Binary Function related to binary_function. But as of TR1 a protocol was introduced that relies on inheritance relations based on these types. 22.10.6 [refwrap]/3 b. 3 requires that a specialization of reference_wrapper<T> shall derive from unary_function, if type T is "a class type that is derived from std::unary_function<T1, R>" and a similar inheritance-based rule for binary_function exists as well.
As another disadvantage it has been pointed out in the TR1 issue list, N1837 (see section 10.39), that the requirements of mem_fn 22.10.16 [func.memfn]/2+3 to derive from std::unary_function/std::binary_function under circumstances, where the provision of corresponding typedefs would be sufficient, unnecessarily prevent implementations that take advantage of empty-base-class optimizations.
Both requirements should be relaxed in the sense that the reference_wrapper should provide typedef's argument_type, first_argument_type, and second_argument_type based on similar rules as the weak result type rule (22.10.4 [func.require]/3) does specify the presence of result_type member types.
For a related issue see also 1279.
[ 2010-10-24 Daniel adds: ]
Accepting n3145 would resolve this issue as NAD editorial.
[ 2010-11 Batavia: Solved by N3198 ]
Resolved by adopting n3198.
Previous proposed resolution:
[ The here proposed resolution is an attempt to realize the common denominator of the reflector threads c++std-lib-26011, c++std-lib-26095, and c++std-lib-26124. ]
Change [base]/1 as indicated: [The intend is to provide an alternative fix for issue 1279 and some editorial harmonization with existing wording in the library, like 99 [iterator.basic]/1]
1 The following class templates are provided to simplify the definition of typedefs of the argument and result types for function objects. The behavior of a program that adds specializations for any of these templates is undefined.
:namespace std { template <class Arg, class Result> struct unary_function { typedef Arg argument_type; typedef Result result_type; }; } namespace std { template <class Arg1, class Arg2, class Result> struct binary_function { typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Result result_type; }; }Change 22.10.6 [refwrap], class template reference_wrapper synopsis as indicated: [The intent is to remove the requirement that reference_wrapper derives from unary_function or binary_function if the situation requires the definition of the typedefs argument_type, first_argument_type, or second_argument_type. This change is suggested, because the new way of definition uses the same strategy as the weak result type specification applied to argument types, which provides the following advantages: It creates less potential conflicts between [u|bi]nary_function bases and typedefs in a function object and it ensures that user-defined function objects which provide typedefs but no such bases are handled as first class citizens.]
namespace std { template <class T> class reference_wrapper: public unary_function<T1, R> // see below: public binary_function<T1, T2, R> // see below{ public : // types typedef T type; typedef see below result_type; // not always defined typedef see below argument_type; // not always defined typedef see below first_argument_type; // not always defined typedef see below second_argument_type; // not always defined // construct/copy/destroy ... };Change 22.10.6 [refwrap]/3 as indicated: [The intent is to remove the requirement that reference_wrapper derives from unary_function if the situation requires the definition of the typedef argument_type and result_type. Note that this clause does concentrate on argument_type alone, because the result_type is already ruled by p. 2 via the weak result type specification. The new way of specifying argument_type is equivalent to the weak result type specification]
3 The template instantiation reference_wrapper<T> shall
be derived from std::unary_function<T1, R>define a nested type named argument_type as a synonym for T1 only if the type T is any of the following:
- a function type or a pointer to function type taking one argument of type T1
and returning R- a pointer to member function R T0::f cv (where cv represents the member function's cv-qualifiers); the type T1 is cv T0*
- a class type
that is derived from std::unary_function<T1, R>with a member type argument_type; the type T1 is T::argument_typeChange 22.10.6 [refwrap]/4 as indicated: [The intent is to remove the requirement that reference_wrapper derives from binary_function if the situation requires the definition of the typedef first_argument_type, second_argument_type, and result_type. Note that this clause does concentrate on first_argument_type and second_argument_type alone, because the result_type is already ruled by p. 2 via the weak result type specification. The new way of specifying first_argument_type and second_argument_type is equivalent to the weak result type specification]
The template instantiation reference_wrapper<T> shall
be derived from std::binary_function<T1, T2, R>define two nested types named first_argument_type and second_argument_type as a synonym for T1 and T2, respectively, only if the type T is any of the following:
- a function type or a pointer to function type taking two arguments of types T1 and T2
and returning R- a pointer to member function R T0::f(T2) cv (where cv represents the member function's cv-qualifiers); the type T1 is cv T0*
- a class type
that is derived from std::binary_function<T1, T2, R>with member types first_argument_type and second_argument_type; the type T1 is T::first_argument_type and the type T2 is T::second_argument_typeChange 22.10.16 [func.memfn]/2+3 as indicated: [The intent is to remove the requirement that mem_fn's return type has to derive from [u|bi]nary_function. The reason for suggesting the change here is to better support empty-base-class optimization choices as has been pointed out in N1837]
2 The simple call wrapper shall
be derived from std::unary_function<cv T*, Ret>define two nested types named argument_type and result_type as a synonym for cv T* and Ret, respectively, when pm is a pointer to member function with cv-qualifier cv and taking no arguments, where Ret is pm's return type.3 The simple call wrapper shall
be derived from std::binary_function<cv T*, T1, Ret>define three nested types named first_argument_type, second_argument_type, and result_type as a synonym for cv T*, T1, and Ret, respectively, when pm is a pointer to member function with cv-qualifier cv and taking one argument of type T1, where Ret is pm's return type.
Proposed resolution:
Addressed by paper n3198.