<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2385: function::assign allocator argument doesn't make sense</title>
<meta property="og:title" content="Issue 2385: function::assign allocator argument doesn't make sense">
<meta property="og:description" content="C++ library issue. Status: C++17">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2385.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#C++17">C++17</a> status.</em></p>
<h3 id="2385"><a href="lwg-defects.html#2385">2385</a>. <code>function::assign</code> allocator argument doesn't make sense</h3>
<p><b>Section:</b> 22.10.17.3 <a href="https://wg21.link/func.wrap.func">[func.wrap.func]</a> <b>Status:</b> <a href="lwg-active.html#C++17">C++17</a>
 <b>Submitter:</b> Pablo Halpern <b>Opened:</b> 2014-05-23 <b>Last modified:</b> 2017-07-30</p>
<p><b>Priority: </b>2
</p>
<p><b>View all other</b> <a href="lwg-index.html#func.wrap.func">issues</a> in [func.wrap.func].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++17">C++17</a> status.</p>
<p><b>Discussion:</b></p>
<p>
The definition of <code>function::assign</code> in N3936 is:
</p>
<blockquote><pre>
template&lt;class F, class A&gt;
  void assign(F&amp;&amp; f, const A&amp; a);
</pre>
<blockquote>
<p>
<i>Effects</i>: <code>function(allocator_arg, a, std::forward&lt;F&gt;(f)).swap(*this)</code>
</p>
</blockquote>
</blockquote>
<p>
This definition is flawed in several respects:
</p>
<ol>
<li><p>The interface implies that the intent is to replace the allocator in <code>*this</code>
with the specified allocator, <code>a</code>.  Such functionality is unique in the
standard and is problematic when creating, e.g. a container of function
objects, all using the same allocator.</p>
</li>
<li><p>The current definition of <code>swap()</code> makes it unclear whether the objects being
swapped can have different allocators.  The general practice is that
allocators must be equal in order to support swap, and this practice is
reinforced by the proposed library TS. Thus, the definition of <code>assign</code> would
have undefined behavior unless the allocator matched the allocator already
within function.
</p>
</li>
<li><p>
The general rule for members of function is to supply the allocator before
the functor, using the <code>allocator_arg</code> prefix. Supplying the allocator as a
second argument, without the <code>allocator_arg</code> prefix is error prone and
confusing.
</p></li>
</ol>

<p>
I believe that this ill-conceived interface was introduced in the effort to
add allocators to parts of the standard where it had been missing, when we
were unpracticed in the right way to accomplish that. Allocators were added
to function at a time when the allocator model was in flux and it was the
first class in the standard after <code>shared_ptr</code> to use type-erased allocators, so
it is not surprising to see some errors in specification here. (<code>shared_ptr</code> is
a special case because of its shared semantics, and so is not a good model.)
<p/>
The main question is whether this member should be specified with better
precision or whether it should be deprecated/removed. The only way I can see to
give a "reasonable" meaning to the existing interface is to describe it in
terms of destroying and re-constructing <code>*this</code>:
</p>
<blockquote><pre>
function temp(allocator_arg, a, std::forward&lt;F&gt;(f));
this-&gt;~function();
::new(this) function(std::move(temp));
</pre></blockquote>
<p>
(The temp variable is needed for exception safety). The ugliness of this
specification underscores the ugliness of the concept. What is the purpose of
this member other than to reconstruct the object from scratch, a facility that
library classes do not generally provide? Programmers are always free to
destroy and re-construct objects &mdash; there is no reason why function should
make that especially easy.
<p/>
I propose, therefore, that we make no attempt at giving the current interface
a meaningful definition of questionable utility, but simply get rid of it
all together. This leaves us with only two questions:
</p>
<ol>
<li><p>Should we deprecate the interface or just remove it?</p></li>
<li><p>Should we replace it with an <code>assign(f)</code> member that doesn't take an
allocator?</p></li>
</ol>
<p>
Of these four combinations of binary answers to the above questions, I think
the ones that make the most sense are (remove, no) and (deprecate, yes). The
proposed new interface provides nothing that <code>operator=</code> does not already
provide. However, if the old (deprecated) interface remains, then having the
new interface will guide the programmer away from it.
<p/>
The proposed wording below assumes deprecation. If we choose removal, then
there is no wording needed; simply remove the offending declaration and
definition.
</p>

<p>
<strong>Previous resolution [SUPERSEDED]:</strong>
</p>
<blockquote class="note">
<p>This wording is relative to N3936.</p>

<ol>
<li><p>Change class template <code>function</code> synopsis, 22.10.17.3 <a href="https://wg21.link/func.wrap.func">[func.wrap.func]</a>, as indicated:</p>

<blockquote>
<pre>
template&lt;class R, class... ArgTypes&gt;
class function&lt;R(ArgTypes...)&gt; {
  [&hellip;]
  <i>// 20.9.11.2.2, function modifiers:</i>
  void swap(function&amp;) noexcept;
  template&lt;class F<del>, class A</del>&gt; void assign(F&amp;&amp;<del>, const A&amp;</del>);
  [&hellip;]
};
</pre>
</blockquote>
</li>

<li><p>Change 22.10.17.3.3 <a href="https://wg21.link/func.wrap.func.mod">[func.wrap.func.mod]</a> as indicated:</p>

<blockquote>
<pre>
template&lt;class F<del>, class A</del>&gt; void assign(F&amp;&amp; f<del>, const A&amp; a</del>);
</pre>
<blockquote>
<p>
<i>Effects</i>: <code><ins>*this = forward&lt;F&gt;(f);</ins><del>function(allocator_arg, a, std::forward&lt;F&gt;(f)).swap(*this)</del></code>
</p>
</blockquote>
</blockquote>
</li>

<li><p>To deprecation section  [depr.function.objects], add the following new sub-clause:</p>

<blockquote>
<p>
<b>Old <code>assign</code> member of polymorphic function wrappers [depr.function.objects.assign]</b>
</p>
<blockquote>
<pre>
namespace std{
  template&lt;class R, class... ArgTypes&gt;
  class function&lt;R(ArgTypes...)&gt; {
    <i>// remainder unchanged</i>
    template&lt;class F, class A&gt; void assign(F&amp;&amp; f, const A&amp; a);
    [&hellip;]
  };
}
</pre>
</blockquote>
<p>
The two-argument form of <code>assign</code> is defined as follows:
</p>
<pre>
template&lt;class F, class A&gt; void assign(F&amp;&amp; f, const A&amp; a);
</pre>
<blockquote>
<p>
<i>Requires</i>: <code>a</code> shall be equivalent to the allocator used to construct <code>*this</code>.
<p/>
<i>Effects</i>: <code>this-&gt;assign(forward&lt;F&gt;(f));</code>
</p>
</blockquote>

</blockquote>
</li>
</ol>
</blockquote>

<p><i>[2015-05, Lenexa]</i></p>

<p>
STL: I would ask, does anybody oppose removing this outright?<br/>
Wakely: I don't even have this signature.<br/>
Hwrd: And I think this doesn't go far enough, even more should be removed. This is a step in the right direction.<br/>
PJP: I'm in favor of removal.<br/>
Wakely: We've already got TS1 that has a new function that does it right. We could wait for feedback on that. 
I think this issue should be taken now.<br/>
Marshall: Then the goal will be to move to ready. 
</p>


<p id="res-2385"><b>Proposed resolution:</b></p>
<p>This wording is relative to N4431.</p>

<ol>
<li><p>Change class template <code>function</code> synopsis, 22.10.17.3 <a href="https://wg21.link/func.wrap.func">[func.wrap.func]</a>, as indicated:</p>

<blockquote>
<pre>
template&lt;class R, class... ArgTypes&gt;
class function&lt;R(ArgTypes...)&gt; {
  [&hellip;]
  <i>// 20.9.12.2.2, function modifiers:</i>
  void swap(function&amp;) noexcept;
  <del>template&lt;class F, class A&gt; void assign(F&amp;&amp;, const A&amp;);</del>
  [&hellip;]
};
</pre>
</blockquote>
</li>

<li><p>Change 22.10.17.3.3 <a href="https://wg21.link/func.wrap.func.mod">[func.wrap.func.mod]</a> as indicated:</p>

<blockquote>
<pre>
<del>template&lt;class F, class A&gt; 
  void assign(F&amp;&amp; f, const A&amp; a);</del>
</pre>
<blockquote>
<p>
<del>-2- <i>Effects</i>: <code>function(allocator_arg, a, std::forward&lt;F&gt;(f)).swap(*this)</code></del>
</p>
</blockquote>
</blockquote>
</li>

</ol>





</body>
</html>
