<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2591: std::function's member template target() should not lead to undefined behaviour</title>
<meta property="og:title" content="Issue 2591: std::function's member template target() should not lead to undefined behaviour">
<meta property="og:description" content="C++ library issue. Status: C++17">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2591.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="2591"><a href="lwg-defects.html#2591">2591</a>. <code>std::function</code>'s member template <code>target()</code> should not lead to undefined behaviour</h3>
<p><b>Section:</b> 22.10.17.3.6 <a href="https://wg21.link/func.wrap.func.targ">[func.wrap.func.targ]</a> <b>Status:</b> <a href="lwg-active.html#C++17">C++17</a>
 <b>Submitter:</b> Daniel Kr&uuml;gler <b>Opened:</b> 2016-01-31 <b>Last modified:</b> 2017-09-07</p>
<p><b>Priority: </b>3
</p>
<p><b>View all other</b> <a href="lwg-index.html#func.wrap.func.targ">issues</a> in [func.wrap.func.targ].</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>
This issue is a spin-off of LWG <a href="lwg-defects.html#2393" title="std::function's Callable definition is broken (Status: C++17)">2393</a><sup><a href="https://cplusplus.github.io/LWG/issue2393" title="Latest snapshot">(i)</a></sup>, it solely focuses on the pre-condition of 22.10.17.3.6 <a href="https://wg21.link/func.wrap.func.targ">[func.wrap.func.targ]</a> p2:
</p>
<blockquote class="note"><p>
<i>Requires</i>: <code>T</code> shall be a type that is Callable (20.9.12.2) for parameter types <code>ArgTypes</code> and return type
<code>R</code>.
</p></blockquote>
<p>
Originally, the author of this issue here had assumed that simply removing the precondition as a side-step of fixing LWG
<a href="lwg-defects.html#2393" title="std::function's Callable definition is broken (Status: C++17)">2393</a><sup><a href="https://cplusplus.github.io/LWG/issue2393" title="Latest snapshot">(i)</a></sup> would be uncontroversial. Discussions on the 
<a href="http://listarchives.isocpp.org/cgi-bin/wg21/message?wg=lib&amp;msg=38356">library reflector</a> indicated that this is not the case, 
although it seemed that there was agreement on removing the undefined behaviour edge-case.
<p/>
There exist basically the following positions:
</p>
<ol>
<li><p>The constraint should be removed completely, the function is considered as having a 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3279.pdf">wide contract</a>.</p>
</li>
<li><p>The pre-condition should be replaced by a <i>Remarks</i> element, that has the effect of making the code ill-formed,
if <code>T</code> is a type that is not Lvalue-Callable (20.9.11.2) for parameter types <code>ArgTypes</code> and return type <code>R</code>.
Technically this approach is still conforming with a wide contract function, because the definition of this contract form
depends on runtime constraints.</p></li>
</ol>
<p>
Not yet explicitly discussed, but a possible variant of bullet (2) could be:
</p>
<ol start="3">
<li><p>The pre-condition should be replaced by a <i>Remarks</i> element, that has the effect of SFINAE-constraining
this member: "This function shall not participate in overload resolution unless  <code>T</code> is a type that is 
Lvalue-Callable (20.9.11.2) for parameter types <code>ArgTypes</code> and return type <code>R</code>".
</p></li>
</ol>
<p>
The following describes a list of some selected arguments that have been provided for one or the other position
using corresponding list items. Unless explicitly denoted, no difference has been accounted for option (3) over 
option (2).
</p>
<ol>
<li>
<ol style="list-style-type:lower-alpha">
<li>
<p>It reflects existing implementation practice, Visual Studio 2015 SR1, gcc 6 libstdc++, and clang 3.8.0 libc++ do accept 
the following code:</p>
<blockquote><pre>
#include &lt;functional&gt;
#include &lt;iostream&gt;
#include &lt;typeinfo&gt;
#include "boost/function.hpp"

void foo(int) {}

int main() {
  std::function&lt;void(int)&gt; f(foo);
  std::cout &lt;&lt; f.target&lt;void(*)()&gt;() &lt;&lt; std::endl;
  boost::function&lt;void(int)&gt; f2(foo);
  std::cout &lt;&lt; f2.target&lt;void(*)()&gt;() &lt;&lt; std::endl;
}
</pre></blockquote>
<p>
and consistently output the implementation-specific result for <b>two null pointer</b> values.
</p>
</li>
<li>
<p>
The current
<a href="http://www.boost.org/doc/libs/1_60_0/doc/html/boost/function_base.html">Boost documentation</a>
does not indicate <em>any</em> precondition for calling the <code>target</code> function, so it is natural
that programmers would expect similar specification and behaviour for the corresponding standard component.
</p>
</li>
<li>
<p>
There is a consistency argument in regard to the free function template <code>get_deleter</code>
</p>
<blockquote><pre>
template&lt;class D, class T&gt; 
D* get_deleter(const shared_ptr&lt;T&gt;&amp; p) noexcept;
</pre></blockquote>
<p>
This function also does not impose any pre-conditions on its template argument <code>D</code>.
</p>
</li>
</ol>
</li>
<li>
<ol style="list-style-type:lower-alpha">
<li>
<p>
Programmers have control over the type they're passing to <code>target&lt;T&gt;()</code>. Passing a non-callable type 
can't possibly retrieve a non-null target, so it seems highly likely to be programmer error. Diagnosing that at 
compile time seems highly preferable to allowing this to return null, always, at runtime.
</p>
</li>
<li>
<p>
If <code>T</code> is a reference type then the return type <code>T*</code> is ill-formed anyway. This implies that one can't 
blindly call <code>target&lt;T&gt;</code> without knowing what <code>T</code> is.
</p>
</li>
<li>
<p>
It has been pointed out that some real world code, boiling down to
</p>
<blockquote><pre>
void foo() {}

int main() {
  std::function&lt;void()&gt; f = foo;
  if (f.target&lt;decltype(foo)&gt;()) {
    <i>// fast path</i>
  } else {
    <i>// slow path</i>
  }
}
</pre></blockquote>
<p>
had manifested as a performance issue and preparing a patch that made the library <code>static_assert</code> in that
case solved this problem (Note that <code>decltype(foo)</code> evaluates to <code>void()</code>, but a proper argument of
<code>target()</code> would have been the function <em>pointer</em> type <code>void(*)()</code>, because a function type 
<code>void()</code> is not any <i>Callable</i> type).
</p>
</li>
</ol>
</li>
</ol>
<p>
It might be worth adding that if use case (2 c) is indeed an often occurring idiom, it would make sense to consider
to provide an explicit conversion to a function pointer (w/o template parameters that could be provided incorrectly), 
if the <code>std::function</code> object at runtime conditions contains a pointer to a real function, e.g.
</p>
<blockquote><pre>
R(*)(ArgTypes...) target_func_ptr() const noexcept;
</pre></blockquote>

<p><i>[2016-08 Chicago]</i></p>

<p>Tues PM: Moved to Tentatively Ready</p>


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

<ol>
<li><p>Change 22.10.17.3.6 <a href="https://wg21.link/func.wrap.func.targ">[func.wrap.func.targ]</a> p2 as indicated:</p>

<blockquote><pre>
template&lt;class T&gt; T* target() noexcept;
template&lt;class T&gt; const T* target() const noexcept;
</pre>
<blockquote>
<p>
<del>-2- <i>Requires</i>: <code>T</code> shall be a type that is <code>Callable</code> (22.10.17.3 <a href="https://wg21.link/func.wrap.func">[func.wrap.func]</a>) for parameter types 
<code>ArgTypes</code> and return type <code>R</code>.</del>
<p/>
-3- <i>Returns</i>: If <code>target_type() == typeid(T)</code> a pointer to the stored function target; otherwise a null
pointer.
</p>
</blockquote>
</blockquote>
</li>

</ol>





</body>
</html>
