<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2774: std::function construction vs assignment</title>
<meta property="og:title" content="Issue 2774: std::function construction vs assignment">
<meta property="og:description" content="C++ library issue. Status: C++23">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2774.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++23">C++23</a> status.</em></p>
<h3 id="2774"><a href="lwg-defects.html#2774">2774</a>. <code>std::function</code> construction vs assignment</h3>
<p><b>Section:</b> 22.10.17.3.2 <a href="https://wg21.link/func.wrap.func.con">[func.wrap.func.con]</a> <b>Status:</b> <a href="lwg-active.html#C++23">C++23</a>
 <b>Submitter:</b> Barry Revzin <b>Opened:</b> 2016-09-14 <b>Last modified:</b> 2023-11-22</p>
<p><b>Priority: </b>3
</p>
<p><b>View all other</b> <a href="lwg-index.html#func.wrap.func.con">issues</a> in [func.wrap.func.con].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++23">C++23</a> status.</p>
<p><b>Discussion:</b></p>
<p>
I think there's a minor defect in the <code>std::function</code> interface. The constructor template is:
</p>
<blockquote><pre>
template &lt;class F&gt; function(F f);
</pre></blockquote>
<p>
while the assignment operator template is
</p>
<blockquote><pre>
template &lt;class F&gt; function&amp; operator=(F&amp;&amp; f);
</pre></blockquote>
<p>
The latter came about as a result of LWG <a href="lwg-defects.html#1288" title="std::function assignment from rvalues (Status: C++11)">1288</a><sup><a href="https://cplusplus.github.io/LWG/issue1288" title="Latest snapshot">(i)</a></sup>, but that one was dealing with a specific issue that
wouldn't have affected the constructor. I think the constructor should also take <code>f</code> by forwarding reference,
this saves a move in the lvalue/xvalue cases and is also just generally more consistent. Should just make sure
that it's stored as <code>std::decay_t&lt;F&gt;</code> instead of <code>F</code>.
<p/>
Is there any reason to favor a by-value constructor over a forwarding-reference constructor?
</p>

<p><i>[2019-07-26 Tim provides PR.]</i></p>


<p><strong>Previous resolution [SUPERSEDED]:</strong></p>
<blockquote class="note">
<p>This wording is relative to <a href="https://wg21.link/N4820">N4820</a>.</p>
<ol>
<li><p>Edit 22.10.17.3 <a href="https://wg21.link/func.wrap.func">[func.wrap.func]</a>, class template <code>function</code> synopsis, as indicated:</p>
<blockquote>
<pre>
namespace std {
  template&lt;class&gt; class function; // not defined
  template&lt;class R, class... ArgTypes&gt; {
  public:
    using result_type = R;

    // 22.10.17.3.2 <a href="https://wg21.link/func.wrap.func.con">[func.wrap.func.con]</a>, construct/copy/destroy
    function() noexcept;
    function(nullptr_t) noexcept;
    function(const function&amp;);
    function(function&amp;&amp;) noexcept;
    template&lt;class F&gt; function(F<ins>&amp;&amp;</ins>);

    [&hellip;]
  };

  [&hellip;]
}
</pre>
</blockquote>
</li>
<li><p>Edit 22.10.17.3.2 <a href="https://wg21.link/func.wrap.func.con">[func.wrap.func.con]</a> p7-11 as indicated:</p>
<blockquote>
<pre>
template&lt;class F&gt; function(F<ins>&amp;&amp;</ins> f);
</pre>
<blockquote>
<p><del>-7- <i>Requires:</i> <code>F</code> shall be <i>Cpp17CopyConstructible</i></del><ins>Let
<code>FD</code> be <code>decay_t&lt;F&gt;</code></ins>.</p>
<p>-8- <del><i>Remarks:</i> This constructor template shall not participate in overload resolution unless
<code>F</code></del> <ins><i>Constraints:</i></ins></p>
<ol style="list-style-type:none">
<li><p><ins>(8.1) &mdash; <code>is_same_v&lt;FD, function&gt;</code> is <code>false</code>; and</ins></p></li>
<li><p><ins>(8.2) &mdash; <code>FD</code></ins> is Lvalue-Callable
(22.10.17.3 <a href="https://wg21.link/func.wrap.func">[func.wrap.func]</a>) for argument types <code>ArgTypes...</code>
and return type <code>R</code>.</p>
</li>
</ol>
<p><ins>-?- <i>Expects:</i> <code>FD</code> meets the
<i>Cpp17CopyConstructible</i> requirements.</ins></p>
<p> -9- <i>Ensures:</i> <code>!*this</code> if any of the following hold:</p>
<ol style="list-style-type:none">
<li><p>(9.1) &mdash; <code>f</code> is a null function pointer value.</p></li>
<li><p>(9.2) &mdash; <code>f</code> is a null member pointer value.</p></li>
<li><p>(9.3) &mdash; <del><code>F</code> is an instance</del> <ins><code>remove_cvref_t&lt;F&gt;</code> is
a specialization</ins> of the <code>function</code> class template, and <code>!f</code> <ins>is <code>true</code></ins>.
</p></li>
</ol>
<p> -10- Otherwise, <code>*this</code> targets
<del>a copy of <code>f</code></del><ins>an object of type <code>FD</code>
direct-non-list-</ins>initialized with <del><code>std::move(f)</code></del>
<ins><code>std::forward&lt;F&gt;(f)</code></ins>. [<i>Note:</i> Implementations should
avoid the use of dynamically allocated memory for small callable objects, for example, where <code>f</code>
<del>is</del> <ins>refers to</ins> an object holding only a pointer or reference to an object
and a member function pointer. &mdash; <i>end note</i>]</p>
<p> -11- <i>Throws:</i> <del>Shall</del> <ins>Does</ins> not throw exceptions when <del><code>f</code></del>
<ins><code>FD</code></ins> is a function pointer <ins>type</ins> or
a <ins>specialization of</ins> <code>reference_wrapper</code><del><code>&lt;T&gt;</code> for some <code>T</code></del>.
Otherwise, may throw <code>bad_alloc</code> or any exception thrown by <del><code>F</code>’s copy or move constructor</del>
<ins>the initialization of the target object</ins>.</p>
</blockquote>
</blockquote>
</li>
</ol>
</blockquote>

<p><i>[2020-11-01; Daniel comments and improves the wording]</i></p>

<p>
The proposed wording should &mdash; following the line of Marshall's "Mandating" papers &mdash;
extract from the <i>Cpp17CopyConstructible</i> precondition a corresponding <i>Constraints:</i>
element and in addition to that the wording should replace old-style elements such as <i>Expects:</i>
by the recently agreed on elements.
<p/>
See also the related issue LWG <a href="lwg-active.html#3493" title="The constructor of std::function taking an F is missing a constraint (Status: New)">3493</a><sup><a href="https://cplusplus.github.io/LWG/issue3493" title="Latest snapshot">(i)</a></sup>.
</p>


<p><strong>Previous resolution [SUPERSEDED]:</strong></p>
<blockquote class="note">
<p>This wording is relative to <a href="https://wg21.link/n4868">N4868</a>.</p>

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

<blockquote>
<pre>
namespace std {
  template&lt;class&gt; class function; <i>// not defined</i>

  template&lt;class R, class... ArgTypes&gt; {
  public:
    using result_type = R;

    // 22.10.17.3.2 <a href="https://wg21.link/func.wrap.func.con">[func.wrap.func.con]</a>, construct/copy/destroy
    function() noexcept;
    function(nullptr_t) noexcept;
    function(const function&amp;);
    function(function&amp;&amp;) noexcept;
    template&lt;class F&gt; function(F<ins>&amp;&amp;</ins>);

    [&hellip;]
  };

  [&hellip;]
}
</pre>
</blockquote>
</li>

<li><p>Edit 22.10.17.3.2 <a href="https://wg21.link/func.wrap.func.con">[func.wrap.func.con]</a> as indicated:</p>
<blockquote>
<pre>
template&lt;class F&gt; function(F<ins>&amp;&amp;</ins> f);
</pre>
<blockquote>
<p>
<ins>Let <code>FD</code> be <code>decay_t&lt;F&gt;</code>.</ins>
</p>
-8- <i>Constraints:</i>
<ol style="list-style-type:none">
<li><p><ins>(8.1) &mdash; <code>is_same_v&lt;remove_cvref_t&lt;F&gt;, function&gt;</code> is <code>false</code>,</ins></p></li>
<li><p><ins>(8.2) &mdash; <code>FD</code></ins><del><code>F</code></del> is Lvalue-Callable (22.10.17.3.1 <a href="https://wg21.link/func.wrap.func.general">[func.wrap.func.general]</a>)
for argument types <code>ArgTypes...</code> and return type <code>R</code><ins>,</ins></p></li>
<li><p><ins>(8.3) &mdash; <code>is_copy_constructible_v&lt;FD&gt;</code> is <code>true</code>, and</ins></p></li>
<li><p><ins>(8.4) &mdash; <code>is_constructible_v&lt;FD, F&gt;</code> is <code>true</code></ins>.</p></li>
</ol>
<p>
-9- <i>Preconditions:</i> <code><del>F</del><ins>FD</ins></code> meets the <i>Cpp17CopyConstructible</i> requirements.
<p/>
-10- <i>Postconditions:</i> <code>!*this</code> if any of the following hold:
</p>
<ol style="list-style-type:none">
<li><p>(10.1) &mdash; <code>f</code> is a null function pointer value.</p></li>
<li><p>(10.2) &mdash; <code>f</code> is a null member pointer value.</p></li>
<li><p>(10.3) &mdash; <del><code>F</code> is an instance</del><ins><code>remove_cvref_t&lt;F&gt;</code> is
a specialization</ins> of the function class template, and <code>!f</code> <ins>is <code>true</code></ins>.</p></li>
</ol>
<p>
-11- Otherwise, <code>*this</code> targets <del>a copy of <code>f</code></del><ins>an object of type <code>FD</code>
direct-non-list-</ins>initialized with <code><del>std::move(f)</del><ins>std::forward&lt;F&gt;(f)</ins></code>.
<p/>
-12- <i>Throws:</i> Nothing if <code><del>f</del><ins>FD</ins></code> is a specialization of <code>reference_wrapper</code>
or a function pointer <ins>type</ins>. Otherwise, may throw <code>bad_alloc</code> or any exception thrown by
<del><code>F</code>'s copy or move constructor</del><ins>the initialization of the target object</ins>.
<p/>
-13- <i>Recommended practice:</i> Implementations should avoid the use of dynamically allocated memory for
small callable objects, for example, where <code>f</code> <del>is</del><ins>refers to</ins> an object holding
only a pointer or reference to an object and a member function pointer.
</p>
</blockquote>
</blockquote>
</li>
</ol>
</blockquote>

<p><i>[2021-05-17; Tim comments and revises the wording]</i></p>

<p>
The additional constraints added in the previous wording can induce
constraint recursion, as noted in the discussion of LWG <a href="lwg-active.html#3493" title="The constructor of std::function taking an F is missing a constraint (Status: New)">3493</a><sup><a href="https://cplusplus.github.io/LWG/issue3493" title="Latest snapshot">(i)</a></sup>.
The wording below changes them to <i>Mandates:</i> instead to allow this issue
to make progress independently of that issue.
<p/>
The proposed resolution below has been implemented and tested on top of
libstdc++.
</p>

<p><i>[2021-05-20; Reflector poll]</i></p>

<p>
Set status to Tentatively Ready after five votes in favour during reflector poll.
</p>

<p><i>[2021-06-07 Approved at June 2021 virtual plenary. Status changed: Voting &rarr; WP.]</i></p>



<p id="res-2774"><b>Proposed resolution:</b></p>
<p>This wording is relative to <a href="https://wg21.link/n4885">N4885</a>.</p>

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

<blockquote>
<pre>
namespace std {
  template&lt;class&gt; class function; <i>// not defined</i>

  template&lt;class R, class... ArgTypes&gt; {
  public:
    using result_type = R;

    // 22.10.17.3.2 <a href="https://wg21.link/func.wrap.func.con">[func.wrap.func.con]</a>, construct/copy/destroy
    function() noexcept;
    function(nullptr_t) noexcept;
    function(const function&amp;);
    function(function&amp;&amp;) noexcept;
    template&lt;class F&gt; function(F<ins>&amp;&amp;</ins>);

    [&hellip;]
  };

  [&hellip;]
}
</pre>
</blockquote>
</li>

<li><p>Edit 22.10.17.3.2 <a href="https://wg21.link/func.wrap.func.con">[func.wrap.func.con]</a> as indicated:</p>
<blockquote>
<pre>
template&lt;class F&gt; function(F<ins>&amp;&amp;</ins> f);
</pre>
<blockquote>
<p>
<ins>Let <code>FD</code> be <code>decay_t&lt;F&gt;</code>.</ins>
</p>
-8- <i>Constraints:</i>
<ol style="list-style-type:none">
<li><p><ins>(8.1) &mdash; <code>is_same_v&lt;remove_cvref_t&lt;F&gt;, function&gt;</code> is <code>false</code>, and</ins></p></li>
<li><p><ins>(8.2) &mdash; <code>FD</code></ins><del><code>F</code></del> is Lvalue-Callable (22.10.17.3.1 <a href="https://wg21.link/func.wrap.func.general">[func.wrap.func.general]</a>)
for argument types <code>ArgTypes...</code> and return type <code>R</code>.</p></li>
</ol>
<p>
<ins>-?- <i>Mandates:</i></ins>
</p>
<ol style="list-style-type:none">
<li><p><ins>(?.1) &mdash; <code>is_copy_constructible_v&lt;FD&gt;</code> is <code>true</code>, and</ins></p></li>
<li><p><ins>(?.2) &mdash; <code>is_constructible_v&lt;FD, F&gt;</code> is <code>true</code>.</ins></p></li>
</ol>
<p>
-9- <i>Preconditions:</i> <code><del>F</del><ins>FD</ins></code> meets the <i>Cpp17CopyConstructible</i> requirements.
<p/>
-10- <i>Postconditions:</i> <code>!*this</code> <ins>is <code>true</code></ins> if any of the following hold:
</p>
<ol style="list-style-type:none">
<li><p>(10.1) &mdash; <code>f</code> is a null function pointer value.</p></li>
<li><p>(10.2) &mdash; <code>f</code> is a null member pointer value.</p></li>
<li><p>(10.3) &mdash; <del><code>F</code> is an instance</del><ins><code>remove_cvref_t&lt;F&gt;</code> is
a specialization</ins> of the <code>function</code> class template, and <code>!f</code> <ins>is <code>true</code></ins>.</p></li>
</ol>
<p>
-11- Otherwise, <code>*this</code> targets <del>a copy of <code>f</code></del><ins>an object of type <code>FD</code>
direct-non-list-</ins>initialized with <code><del>std::move(f)</del><ins>std::forward&lt;F&gt;(f)</ins></code>.
<p/>
-12- <i>Throws:</i> Nothing if <code><del>f</del><ins>FD</ins></code> is a specialization of <code>reference_wrapper</code>
or a function pointer <ins>type</ins>. Otherwise, may throw <code>bad_alloc</code> or any exception thrown by
<del><code>F</code>'s copy or move constructor</del><ins>the initialization of the target object</ins>.
<p/>
-13- <i>Recommended practice:</i> Implementations should avoid the use of dynamically allocated memory for
small callable objects, for example, where <code>f</code> <del>is</del><ins>refers to</ins> an object holding
only a pointer or reference to an object and a member function pointer.
</p>
</blockquote>
</blockquote>
</li>
</ol>





</body>
</html>
