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.

### 1290. Don't require `[u|bi]nary_function` inheritance

Section: 20.14 [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. 20.14.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` 20.14.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 (20.14.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. ]

> 1. 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;
>    > >      };
>    > >     }

> 2. Change 20.14.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
>    >        ...
>    >      };

> 3. Change 20.14.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_type`

> 4. Change 20.14.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_type`

> 5. Change 20.14.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.