Document number: |  | N4022
Date: |  | 2014-05-21
Project: |  | Programming Language C++, Library Working Group
Reply-to: |  |

# A proposal to add a generalized callable negator (Revision 2)

## Introduction

This proposal is to add function template `not_fn` that will allow to create negator of any callable object.

## Revision history

Changes since N3800:

- Updated proposed wording per LWG guidance.

Changes since N3699:

- Change the requirements of `not_fn` to allow wrapping of move-only types.
- Added missing Throws clause.
- Included changes to 20.10 [function.objects]/2 section.
- Corrected link to "Generic (Polymorphic) Lambda Expressions" proposal.
- Changed formating of the document.

## Motivation and Scope

The standard negators `not1` and `not2` accept only unary and binary functors that define `argument_type` or `first_argument_type` and `second_argument_type` respectively, which make them unusable with results of standard library functions such as `bind` and `mem_fn`. Furthermore, with relation to N3421, they cannot be used with new operator functor specializations.

This proposal addresses the problem by introducing a template function `not_fn` that returns complement of arbitrary predicate.

### Comparison with lambda

While the polymorphic lambda expressions (N3649) may be used to negate arbitrary functor, the proposed function offers more compact syntax:

      std::partition(v.begin(), v.end(), [f](auto& p) { return !f(p); });
      std::partition(v.begin(), v.end(), std::not_fn(f));

Furthermore, the use of lambda expression requires separate treatment of member pointers:

      std::partition(v.begin(), v.end(), [pm](auto& p) { return !std::mem_fn(pm)(p); });
      std::partition(v.begin(), v.end(), std::not_fn(pm));

### Deprecation

With the incorporation of proposed functionality the old standard negators should be deprecated.

## Design Decisions

### New specializations of `unary_negate`, `binary_negate`

Problem addressed by this paper may be solved by introducing perfect forwarding specializations of `unary_negate` and `binary_negate` for types that do not define `argument_type` and `first_argument_type`, `second_argument_type` nested types respectively, without breaking existing code. Although this solution does not address functions with arbitrary number of arguments and requires additional implementation burden.

### Return type

The perfect forwarding of return type was chosen instead of hard-coded `bool`. Similar argumentation to the one provided in N3421 applies.

### Argument typedefs

The `argument_type`, `first_argument_type` and `second_argument_type` nested types are required by implemenatation to be consistent with most of library functors, that define these types where they are well defined for target callable type. Futhermore it is increasing the amount of existing code that will remain valid after changing `not1`, `not2` to `not_fn`.

## Impact On The Standard

This proposal has no dependencies beyond a C++11 compiler and Standard Library implementation. (It depends on perfect forwarding, `decltype` and trailing return types.)

Nothing depends on this proposal.

## Proposed wording

After the declaration of `not2` in the section 20.10 [function.objects]/2 (Header `<functional>` synopsis), add:

>       // 20.10.9, negators
>       template <class F> unspecified not_fn(F&& f);

After paragraph 20.10.8 Negators [negators], insert a new paragraph. (Chapter [bind] (Function template `bind`) becomes 20.10.?)

> #### 20.10.9 Function template `not_fn` [not_fn]

>       template <class F>
>         unspecified not_fn(F&& f);

>   In the text that follows:

>   - `FD` is the type `decay<F>::type`,
>   - `fd` is an lvalue of type `FD` constructed from `std::forward<F>(f),`
>   - `fn` is a simple call wrapper created as a result of `not_fn(f)`,
>   - `FN` is the type of `fn`,

> Requires:
>   `is_constructible<FD, F>::value` shall be `true`. `f` shall be a callable object ([func.require] 20.10.2).

> Returns:

>   A forwarding call wrapper `fn` such that the expression `fn(a1, a2, ..., aN)` is equivalent to `!INVOKE(fd, a1, a2, ..., aN)` ([func.require] 20.10.2).

> Throws:

>   Nothing unless the construction of `fd` throws an exception.

> Remarks:

>   The return type shall satisfy the requirements of `MoveConstructible`. If `FD` satisfies the requirements of `CopyConstructible`, then the return type shall satisfy the requirements of `CopyConstructible`. [ Note: This implies that `FD` is MoveConstructible. — end note ]

>   If `reference_wrapper<FD>` has a nested type `result_type`, `FN` shall define a nested type named `result_type` as a synonym for `decltype(!declval<typename reference_wrapper<FD>::result_type>())`.

>   `FN` shall define a nested type named `argument_type` as a synonym for `T1` only if the type `F` is any of the following:

>   - a function type or a pointer to function type taking one argument of type `T1`
>   - 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 with a member type `argument_type`; the type `T1` is `F::argument_type.`

>   `FN` shall define two nested types named `first_argument_type` and `second_argument_type` as synonyms for `T1` and `T2`, respectively, only if the type `F` is any of the following:

>   - a function type or a pointer to function type taking two arguments of types `T1` and `T2`
>   - 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 with member types `first_argument_type` and `second_argument_type`; the type `T1` is `F::first_argument_type` and the type `T2` is `F::second_argument_type.`

## Acknowledgements

Anna Salwa originally proposed `not_fn` in discussion group ISO C++ Standard - Future Proposals.

Mateusz Kwiatkowski, Jonathan Wakely and Daniel Krügler offered many useful suggestions and corrections to the proposal.

## References

1. Stephan T. Lavavej, "Making Operator Functors greater<>" (N3421, http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3421.htm)
2. Faisal Vali, Herb Sutter, Dave Abrahams, "Generic (Polymorphic) Lambda Expressions (Revision 3) " (N3649, http://isocpp.org/files/papers/N3649.html)