<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 1076: unary/binary_negate need constraining and move support</title>
<meta property="og:title" content="Issue 1076: unary/binary_negate need constraining and move support">
<meta property="og:description" content="C++ library issue. Status: NAD Concepts">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue1076.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#NAD_Concepts">NAD Concepts</a> status.</em></p>
<h3 id="1076"><a href="lwg-closed.html#1076">1076</a>. unary/binary_negate need constraining and move support</h3>
<p><b>Section:</b> 99 [depr.negators] <b>Status:</b> <a href="lwg-active.html#NAD_Concepts">NAD Concepts</a>
 <b>Submitter:</b> Alisdair Meredith <b>Opened:</b> 2009-03-20 <b>Last modified:</b> 2017-06-15</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View all issues with</b> <a href="lwg-status.html#NAD Concepts">NAD Concepts</a> status.</p>
<p><b>Discussion:</b></p>
<p>
The class templates <code>unary/binary_negate</code> need constraining and move support.
</p>
<p>
Ideally these classes would be deprecated, allowing <code>unary/binary_function</code> to
also be deprecated.  However, until a generic negate adaptor is introduced
that can negate any <code>Callable</code> type, they must be supported so should be
constrained.  Likewise, they should be movable, and support adopting a
move-only predicate type.
</p>
<p>
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.
</p>
<p>
Do not consider the issue of forwarding mutable lvalues at this point,
although remain open to another issue on the topic.
</p>

<p><i>[
2009-05-01 Daniel adds:
]</i></p>

<blockquote>
<p>
IMO the currently proposed resolution needs some updates
because it is ill-formed at several places:
</p>

<ol>
<li>
<p>
In concept AdaptableUnaryFunction change
</p>
<blockquote><pre>
typename X::result_type;
typename X::argument_type;
</pre></blockquote>
<p>
to
</p>
<blockquote><pre>
Returnable result_type = typename X::result_type;
typename argument_type = typename X::argument_type;
</pre></blockquote>
<p>
[The replacement "Returnable result_type" instead of "typename
result_type" is non-editorial, but maybe you prefer that as well]
</p>
</li>
<li>
<p>
In concept AdaptableBinaryFunction change
</p>
<blockquote><pre>
typename X::result_type;
typename X::first_argument_type;
typename X::second_argument_type;
</pre></blockquote>
<p>
to
</p>
<blockquote><pre>
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;
</pre></blockquote>
<p>
[The replacement "Returnable result_type" instead of "typename
result_type" is non-editorial, but maybe you prefer that as well.]
</p>
</li>

<li>
<p>
In class unary/binary_function
</p>
<ol style="list-style-type:lower-alpha">
<li>
I suggest to change "ReturnType" to "Returnable" in both cases.
</li>
<li>
I think you want to replace the remaining occurrences of "Predicate" by "P"
(in both classes in copy/move from a predicate)
</li>
</ol>
</li>
<li>
<p>
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&lt;true&gt;") or just explicit as follows:
</p>
<ol style="list-style-type:lower-alpha">
<li>
<blockquote><pre>
template &lt;AdaptableUnaryFunction P&gt;
requires Predicate&lt; P, P::argument_type&gt;
unary_negate&lt;P&gt; not1(const P&amp;&amp; pred);
template &lt;AdaptableUnaryFunction P&gt;
requires Predicate&lt; P, P::argument_type &gt;
unary_negate&lt;P&gt; not1(P&amp;&amp; pred);
</pre>
<blockquote><p>
-3- Returns: unary_negate&lt;P&gt;(pred).
</p></blockquote>
</blockquote>
<p>
[Don't we want a move call for the second overload as in
</p>
<blockquote><pre>
unary_negate&lt;P&gt;(std::move(pred))
</pre></blockquote>
<p>
in the Returns clause ?]
</p>
</li>
<li>
<pre>
template &lt;AdaptableBinaryFunction P&gt;
requires Predicate&lt; P, P::first_argument_type, P::second_argument_type &gt;
binary_negate&lt;P&gt; not2(const P&amp; pred);
template &lt;AdaptableBinaryFunction P&gt;
requires Predicate&lt; P, P::first_argument_type, P::second_argument_type &gt;
binary_negate&lt;P&gt; not2(P&amp;&amp; pred);
</pre>
<p>
-5- Returns: binary_negate&lt;P&gt;(pred).
</p>
<p>
[Don't we want a move call for the second overload as in
</p>
<blockquote><pre>
binary_negate&lt;P&gt;(std::move(pred))
</pre></blockquote>
<p>
in the Returns clause ?]
</p>
</li>
</ol>
</li>
</ol>
</blockquote>

<p><i>[
Batavia (2009-05):
]</i></p>

<blockquote>
<p>
There is concern that complicating the solution
to preserve the ABI seems unnecessary,
since we're not in general preserving the ABI.
</p>
<p>
We would prefer a separate paper consolidating all Clause 20
issues that are for the purpose of providing constrained versions
of the existing facilities.
</p>
<p>
Move to Open.
</p>
</blockquote>

<p><i>[
2009-10 post-Santa Cruz:
]</i></p>


<blockquote><p>
Leave open pending the potential move constructor paper. Note that
we consider the "constraining" part NAD Concepts.
</p></blockquote>

<p><i>[
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:
]</i></p>


<blockquote class="note">
<p>
Add new concepts where appropriate::
</p>

<blockquote><pre>
auto concept AdaptableUnaryFunction&lt; typename X &gt; {
  typename X::result_type;
  typename X::argument_type;
}

auto concept AdaptableBinaryFunction&lt; typename X &gt; {
  typename X::result_type;
  typename X::first_argument_type;
  typename X::second_argument_type;
}
</pre></blockquote>

<p>
Revise as follows:
</p>

<p>
Base  [base] (Only change is constrained Result)
</p>

<blockquote>
<p>
-1-  The following classes are provided to simplify the typedefs of the
argument and result types:
</p>
<pre>
namespace std {
  template &lt;class Arg, <del>class</del> <ins>ReturnType</ins> Result&gt;
  struct unary_function {
     typedef Arg    argument_type;
     typedef Result result_type;
  };

  template &lt;class Arg1, class Arg2, <del>class</del> <ins>ReturnType</ins> Result&gt;
  struct binary_function {
     typedef Arg1   first_argument_type;
     typedef Arg2   second_argument_type;
     typedef Result result_type;
  };
}
</pre></blockquote>

<p>
Negators  [negators]:
</p>

<blockquote>
<p>
-1- Negators <code>not1</code> and <code>not2</code> take a unary and a binary predicate,
respectively, and return their complements (5.3.1).
</p>

<pre>
template &lt;<del>class</del> <ins>AdaptableUnaryFunction</ins> P<del>redicate</del>&gt;
  <ins>requires Predicate&lt; P, P::argument_type &gt;</ins>
  class unary_negate
    : public unary_function&lt;<del>typename</del> P<del>redicate</del>::argument_type,bool&gt; {
  public:
    <ins>unary_negate(const unary_negate &amp; ) = default;</ins>
    <ins>unary_negate(unary_negate &amp;&amp; );</ins>

    <ins>requires CopyConstructible&lt; P &gt;</ins>
       explicit unary_negate(const Predicate&amp; pred); 
    <ins>requires MoveConstructible&lt; P &gt;
       explicit unary_negate(Predicate &amp;&amp; pred);</ins>

    bool operator()(const <del>typename</del> P<del>redicate</del>::argument_type&amp; x) const;
  };
</pre>
<blockquote><p>
-2 <code>operator()</code> returns <code>!pred(x)</code>.
</p></blockquote>

<pre>
template &lt;class Predicate&gt;
  unary_negate&lt;Predicate&gt; not1(const Predicate&amp;amp; pred);
<ins>template &lt;class Predicate&gt;
  unary_negate&lt;Predicate&gt; not1(Predicate&amp;&amp; pred);</ins>
</pre>
<blockquote><p>
-3-  <i>Returns:</i> <code>unary_negate&lt;Predicate&gt;(pred)</code>.
</p></blockquote>

<pre>
template &lt;<del>class</del> <ins>AdaptableBinaryFunction</ins> P<del>redicate</del> &gt;
  <ins>requires Predicate&lt; P, P::first_argument_type, P::second_argument_type &gt;</ins>
  class binary_negate
    : public binary_function&lt;<del>typename</del> P<del>redicate</del>::first_argument_type,
                              <del>typename</del> P<del>redicate</del>::second_argument_type, bool&gt; {
  public:
    <ins>biary_negate(const binary_negate &amp; ) = default;</ins>
    <ins>binary_negate(binary_negate &amp;&amp; );</ins>

    <ins>requires CopyConstructible&lt; P &gt;</ins>
       explicit binary_negate(const Predicate&amp; pred);
    <ins>requires MoveConstructible&lt; P &gt;
       explicit binary_negate(const Predicate&amp; pred);</ins>

    bool operator()(const <del>typename</del> P<del>redicate</del>::first_argument_type&amp; x,
                    const <del>typename</del> P<del>redicate</del>::second_argument_type&amp; y) const;
  };
</pre>
<blockquote><p>
-4- <code>operator()</code> returns <code>!pred(x,y)</code>.
</p></blockquote>

<pre>
template &lt;class Predicate&gt;
  binary_negate&lt;Predicate&gt; not2(const Predicate&amp; pred);
<ins>template &lt;class Predicate&gt;
  binary_negate&lt;Predicate&gt; not2(Predicate&amp;&amp; pred);</ins>
</pre>

<blockquote><p>
-5- <i>Returns:</i> <code>binary_negate&lt;Predicate&gt;(pred)</code>.
</p></blockquote>
</blockquote>

</blockquote>


<p><i>[
2010 Rapperswil:
]</i></p>


<blockquote><p>
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.
</p></blockquote>



<p id="res-1076"><b>Proposed resolution:</b></p>





</body>
</html>
