This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of NAD Concepts status.
Section: 99 [depr.negators] Status: NAD Concepts Submitter: Alisdair Meredith Opened: 2009-03-20 Last modified: 2017-06-15
Priority: Not Prioritized
View all issues with NAD Concepts status.
Discussion:
The class templates unary/binary_negate need constraining and move support.
Ideally these classes would be deprecated, allowing unary/binary_function to also be deprecated. However, until a generic negate adaptor is introduced that can negate any Callable type, they must be supported so should be constrained. Likewise, they should be movable, and support adopting a move-only predicate type.
In order to preserve ABI compatibility, new rvalue overloads are supplied in preference to changing the existing pass-by-const-ref to pass-by-value.
Do not consider the issue of forwarding mutable lvalues at this point, although remain open to another issue on the topic.
[ 2009-05-01 Daniel adds: ]
IMO the currently proposed resolution needs some updates because it is ill-formed at several places:
In concept AdaptableUnaryFunction change
typename X::result_type; typename X::argument_type;to
Returnable result_type = typename X::result_type; typename argument_type = typename X::argument_type;[The replacement "Returnable result_type" instead of "typename result_type" is non-editorial, but maybe you prefer that as well]
In concept AdaptableBinaryFunction change
typename X::result_type; typename X::first_argument_type; typename X::second_argument_type;to
Returnable result_type = typename X::result_type; typename first_argument_type = typename X::first_argument_type; typename second_argument_type = typename X::second_argument_type;[The replacement "Returnable result_type" instead of "typename result_type" is non-editorial, but maybe you prefer that as well.]
In class unary/binary_function
- I suggest to change "ReturnType" to "Returnable" in both cases.
- I think you want to replace the remaining occurrences of "Predicate" by "P" (in both classes in copy/move from a predicate)
I think you need to change the proposed signatures of not1 and not2, because they would still remain unconstrained: To make them constrained at least a single requirement needs to be added to enable requirement implication. This could be done via a dummy ("requires True<true>") or just explicit as follows:
template <AdaptableUnaryFunction P> requires Predicate< P, P::argument_type> unary_negate<P> not1(const P&& pred); template <AdaptableUnaryFunction P> requires Predicate< P, P::argument_type > unary_negate<P> not1(P&& pred);-3- Returns: unary_negate<P>(pred).
[Don't we want a move call for the second overload as in
unary_negate<P>(std::move(pred))in the Returns clause ?]
template <AdaptableBinaryFunction P> requires Predicate< P, P::first_argument_type, P::second_argument_type > binary_negate<P> not2(const P& pred); template <AdaptableBinaryFunction P> requires Predicate< P, P::first_argument_type, P::second_argument_type > binary_negate<P> not2(P&& pred);-5- Returns: binary_negate<P>(pred).
[Don't we want a move call for the second overload as in
binary_negate<P>(std::move(pred))in the Returns clause ?]
[ Batavia (2009-05): ]
There is concern that complicating the solution to preserve the ABI seems unnecessary, since we're not in general preserving the ABI.
We would prefer a separate paper consolidating all Clause 20 issues that are for the purpose of providing constrained versions of the existing facilities.
Move to Open.
[ 2009-10 post-Santa Cruz: ]
Leave open pending the potential move constructor paper. Note that we consider the "constraining" part NAD Concepts.
[ 2010-01-31 Alisdair removes the current proposed wording from the proposed wording section because it is based on concepts. That wording is proposed here: ]
Add new concepts where appropriate::
auto concept AdaptableUnaryFunction< typename X > { typename X::result_type; typename X::argument_type; } auto concept AdaptableBinaryFunction< typename X > { typename X::result_type; typename X::first_argument_type; typename X::second_argument_type; }Revise as follows:
Base [base] (Only change is constrained Result)
-1- The following classes are provided to simplify the typedefs of the argument and result types:
namespace std { template <class Arg,classReturnType Result> struct unary_function { typedef Arg argument_type; typedef Result result_type; }; template <class Arg1, class Arg2,classReturnType Result> struct binary_function { typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Result result_type; }; }Negators [negators]:
-1- Negators not1 and not2 take a unary and a binary predicate, respectively, and return their complements (5.3.1).
template <classAdaptableUnaryFunction Predicate> requires Predicate< P, P::argument_type > class unary_negate : public unary_function<typenamePredicate::argument_type,bool> { public: unary_negate(const unary_negate & ) = default; unary_negate(unary_negate && ); requires CopyConstructible< P > explicit unary_negate(const Predicate& pred); requires MoveConstructible< P > explicit unary_negate(Predicate && pred); bool operator()(consttypenamePredicate::argument_type& x) const; };-2 operator() returns !pred(x).
template <class Predicate> unary_negate<Predicate> not1(const Predicate& pred); template <class Predicate> unary_negate<Predicate> not1(Predicate&& pred);-3- Returns: unary_negate<Predicate>(pred).
template <classAdaptableBinaryFunction Predicate> requires Predicate< P, P::first_argument_type, P::second_argument_type > class binary_negate : public binary_function<typenamePredicate::first_argument_type,typenamePredicate::second_argument_type, bool> { public: biary_negate(const binary_negate & ) = default; binary_negate(binary_negate && ); requires CopyConstructible< P > explicit binary_negate(const Predicate& pred); requires MoveConstructible< P > explicit binary_negate(const Predicate& pred); bool operator()(consttypenamePredicate::first_argument_type& x, consttypenamePredicate::second_argument_type& y) const; };-4- operator() returns !pred(x,y).
template <class Predicate> binary_negate<Predicate> not2(const Predicate& pred); template <class Predicate> binary_negate<Predicate> not2(Predicate&& pred);-5- Returns: binary_negate<Predicate>(pred).
[ 2010 Rapperswil: ]
Move to NAD Concepts. The move-semantic part has been addressed by a core language change, which implicitly generates appropriate move constructors and move-assignment operators.
Proposed resolution: