<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

<title>Resolving GB 55, US 84, US 85, US 86</title>

<style type="text/css">
  p {text-align:justify}
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  blockquote.note
  {
   background-color:#E0E0E0;
   padding-left: 15px;
   padding-right: 15px;
   padding-top: 1px;
   padding-bottom: 1px;
  }
</style>
</head><body>
<address style="text-align: left;">
Document number: P0604R0<br/>
Date: 2017-03-03<br/>
Project: Programming Language C++<br/>
Audience: Library Working Group, Library Evolution Working Group<br/>
Authors: Daniel Kr&uuml;gler, Pablo Halpern, Jonathan Wakely<br/>
Reply-to: <a href="mailto:daniel.kruegler@gmail.com">Daniel Kr&uuml;gler</a>
</address>
<hr>
<h1 style="text-align: center;">Resolving GB 55, US 84, US 85, US 86</h1>

<ul>
<li><a href="#Discussion">Discussion</a></li>
<li><a href="#Rationale">Rationale</a></li>
<li><a href="#Issues_Resolved">Resolved Issues</a></li>
<li><a href="#Proposed_resolution">Proposed Resolution</a></li>
<li><a href="#FeatureMacro">Feature-testing Macro</a></li>
</ul>

<h2><a name="Discussion"></a>Discussion</h2>
<p>
This proposal attempts to provide combined wording for the changes requested by the NB comments
GB 55, US 84, US 85, and US 86 against C++17.
<p/>
The general approach is to follow the suggested directions described by the issues:
</p>
<ol>
<li><p><b>Required change:</b> Split <tt><i>INVOKE_R</i></tt> from being an additional <tt><i>INVOKE</i> "overload".</tt></p></li>
<li><p><b>Required change:</b> Rename and split <tt>is_callable/is_nothrow_callable</tt> into <tt>is_invocable/is_nothrow_invocable/is_invocable_r/is_nothrow_invocable_r</tt> (and associated types accordingly)</p></li>
<li><p><b>Required change:</b> Change function type encoding of previous <tt>is_callable/is_nothrow_callable/result_of</tt>
traits to conventional template type parameter lists.</p></li>
<li><p><b>Optional change:</b> Deprecate <tt>result_of</tt> and introduce a new form without function type encoding whose
       name needs to be determined (Bikeshedding - Yeah!).</p></li>
</ol>

<p>
The changes in regard to <tt>result_of</tt> have been made optional, because this step increases the necessary
draft changes significantly. 
<p/>
If we introduce a new replacement trait for <tt>result_of</tt>, this requires a new name. The following is a list
of naming suggestions available at the point of writing this proposal:
</p>
<ol>
<li><p><tt>result_of_invoke</tt> [Suggested by US 85]</p></li>
<li><p><tt>invoke_result</tt> [Suggested by Jonathan Wakely]</p></li>
<li><p><tt>invocation_result</tt> [Suggested by Jonathan Wakely]</p></li>
<li><p><tt>invocation</tt> [Suggested by Jonathan Wakely]</p></li>
</ol>

<blockquote class="note">
<p>
Without yet any concrete preferences expressed by the Committee, the proposal uses the name <tt>invoke_result</tt> 
as working title for that new trait. 
<p/>
Nonetheless it should be noted that <em>all three</em> authors have independently expressed their preference for this 
name over the other choices.
</p>
</blockquote>

<p>
Originally, Jonathan Wakely has made an alternative suggestion that could provide the return type of <tt><i>INVOKE()</i>/invoke()</tt>
without need of introducing a separate type trait for the result type. Instead the renamed <tt>is_invocable</tt> trait 
could in addition to its <tt>type</tt> member type provide another member type &mdash; possibly named 
<tt>result_type</tt> &mdash; conditionally, that is only defined if the trait evaluates to <tt>true</tt>.
<p/>
The authors of this paper are <em>not</em> in favour of this alternative approach for the following reasons:
</p>
<ol>
<li><p>This would introduce a completely new way of retrieving information from traits, which is hard to
explain and feels a bit like an inconsistent design.</p></li>
<li><p>The changes requested by the NB comments responded by this paper come very late, therefore the
solution should not increase the chances of rejecting the whole paper just because of experimenal ideas that
would better fit into an early investigation phase.</p></li>
<li><p>As Jonathan says: "One potential downside of that is that people might accidentally use
<tt>is_invocable::type</tt> instead of <tt>is_invocable::result_type</tt>, which would
always be present (it comes from the <tt>bool_constant BaseCharacteristic</tt>
and is either <tt>true_type</tt> or <tt>false_type</tt>)."</p></li>
<li><p>For implementations the additional templates don't require extra work, since they can internally
delegate to reusable entities.</p></li>
<li><p>Last but not least, it is easily possible to switch in the future to the alternative approach, in case that
more good reasons are determined for such a design change.</p></li>
</ol>

<h2><a name="Rationale"></a>Rationale</h2>
<p>
The authors of this paper recommend to apply all <em>four</em> suggested changes inspired by the NB comments as specified below
for the following reasons:
</p>
<ol>
<li><p><b>Rename <tt>is_callable</tt> to <tt>is_invocable</tt>:</b> <tt>is_callable</tt> would be the most natural name for
a trait that answers the question whether a function call expression would be valid or not, which is a strict subset
of the expressions, <tt><i>INVOKE</i></tt> supports, furthermore the changed name <tt>is_invocable</tt> much
clearer expresses its meaning. Releasing the name <tt>is_callable</tt> allows us in the future to possibly introduce
a pure <tt>is_callable</tt> trait (But this is not part of this proposal).</p></li>
<li><p><b>Separating <tt><i>INVOKE_R</i></tt> from <tt><i>INVOKE</i></tt>:</b> <tt><i>INVOKE</i></tt> is an artificial construct
and it is therefore very hard to logically discriminate a call of <tt><i>INVOKE</i></tt> <em>with</em> or <em>without</em>
provided return type <tt>R</tt>. In every case where a pack expansion is provided, it is at least theoretically unclear 
whether the last parameter should be considered as part of the argument list of the first "overload" or as return type of the
second "overload" (The fact that it is a type instead of a value helps, but the visual recognition is not easy). During the 
initial discussion of this topic, several people had expressed that they would prefer 
a <tt><i>INVOKE_R</i></tt> meta function that lists the return type <em>first</em> instead of as its <em>last</em> parameter 
(presumably because that has some similarities to a function template where this type would not be deduced). Daniel
suggested a variant of the second form that would replace <tt><i>INVOKE_R</i>(R, f, args...)</tt> by
<tt><i>INVOKE</i>&lt;R&gt;(f, args...)</tt> which is the form used below.</p></li>
<li><p><b>Replace function type encoding of type lists in <tt>is_callable</tt> and <tt>result_of</tt>:</b> The function type
encoding form used in these type traits is a relict from the pre-variadic template era of C++ where a single type is used to
express a list of types. First, for both traits the natural interpretation of the encoded form <tt>Fn(ArgTypes...)</tt> looks
as if <tt>Fn</tt> is used as return type, but it is only the callable object to which the arguments are provided. Second, 
contrary to the rest of all type traits which use a glvalue-based expression approach due to the <em>direct</em> usage of 
<tt>declval</tt> applied to the given type parameters, function type encoding is more natural for non-glvalues. In particular,
parameter types are first <em>adjusted</em> via a special decay-like mechanism (8.3.5 [dcl.fct]), such that the actually provided 
types are often not the types on which the actual test is applied. Another problem is that function return types and argument 
types prevent some important type classes to be actually provided in the encoded form: Neither can argument types have an 
abstract class type nor <i>cv</i> <tt>void</tt> type, nor can function types or array types be used as "return type". 
<p/>
As a workaround against the type transformation and restrictions mentioned above, user code needs to carefully ensure proper 
application of references to the arguments which causes problems for types that are non-<em>referenceable</em> types such as
<tt>void() const</tt>, because instead af a silent SFINAE overload exclusion a compiler error will occur. Alisdair Meredith
provided the following example of such an unpleasant situation on the Library reflector:
</p>
<blockquote><pre>
#include &lt;type_traits&gt;

struct Functor {
  template &lt;typename T&gt;
  void operator()(T&amp;&amp;) const {}
};

template &lt;typename T&gt;
void validate() {
  static_assert(!std::is_callable_v&lt;Functor(T)&gt;);
}

using abomination = int() const;

int main() {
  validate&lt;abomination&gt;();
}
</pre></blockquote>
<p>
These subtleties of the function type encoding had lead to a series of Library issues in the past, such as the following ones:</p>
<ul>
<li><p><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2017">LWG 2017</a>:
<tt>std::reference_wrapper</tt> makes incorrect usage of <tt>std::result_of</tt></p></li>
<li><p><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2021">LWG 2021</a>:
Further incorrect usages of <tt>result_of</tt></p></li>
<li><p><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2767">LWG 2767</a>:
<tt>not_fn <em>call_wrapper</em></tt> can form invalid types</p></li>
</ul>
</li>
</ol>

<p>
The Library Evolution Working Group had been asked to look at the design changes involved by this paper and the following 
lists the results of their evaluation:
</p>

<table style="width: 300px" border="1">
<caption>Introduce <tt><em>invoke_result</em></tt>, by some name?</caption>
<tr style="text-align: center">
<td>SF</td><td>F</td><td>N</td><td>A</td><td>SA</td></tr>
<tr style="text-align: center">
<td>12</td><td>2</td><td>0</td><td>0</td><td>0</td></tr>
</table>

<table style="width: 300px" border="1">
<caption>Deprecate <tt>result_of</tt>?</caption>
<tr style="text-align: center">
<td>SF</td><td>F</td><td>N</td><td>A</td><td>SA</td></tr>
<tr style="text-align: center">
<td>7</td><td>7</td><td>0</td><td>0</td><td>0</td></tr>
</table>

<table style="width: 300px" border="1">
<caption>Name for <tt><em>invoke_result</em></tt>:</caption>
<tr style="text-align: left">
<td><tt>result_of_invoke_t&lt;a, b, c&gt;</tt></td><td>0</td></tr>
<tr style="text-align: left">
<td><tt>invoke_result_t&lt;a, b, c&gt;</tt></td><td>11</td></tr>
<tr style="text-align: left">
<td><tt>invocation_result_t&lt;a, b, c&gt;</tt></td><td>7</td></tr>
<tr style="text-align: left">
<td><tt>invocation_t&lt;a, b, c&gt;</tt></td><td>6</td></tr>
<tr style="text-align: center">
<td colspan="2">[<tt>invoke_result</tt> wins]</td></tr>
</table>

<table style="width: 300px" border="1">
<caption>Provide only <tt>is_invocable&lt;&gt;::result_type</tt> instead of <tt>invoke_result</tt>?</caption>
<tr style="text-align: left">
<td>Unanimous no.</td></tr>
</table>

<table style="width: 300px" border="1">
<caption>Provide both <tt>invoke_result&lt;&gt;::type</tt> and <tt>is_invocable&lt;&gt;::result_type</tt>?</caption>
<tr style="text-align: center">
<td>SF</td><td>F</td><td>N</td><td>A</td><td>SA</td></tr>
<tr style="text-align: center">
<td>0</td><td>2</td><td>6</td><td>5</td><td>1</td></tr>
</table>

<p>
The authors of this paper consider these results as a strong confirmation of the direction of their proposal.
</p>

<h2><a name="Issues_Resolved"></a>Resolved Issues</h2>
<p>
If the proposed resolution would be accepted, the following library issues will be resolved:
</p>
<table border="1">
  <tr>
    <th>Number</th>
    <th>Description</th>
  </tr>
  <tr>
    <td><a href="http://cplusplus.github.io/LWG/lwg-active.html#2895">2895</a></td>
    <td>Passing function types to <tt>result_of</tt> and <tt>is_callable</tt></td>
  </tr>
  <tr>
    <td><a href="http://cplusplus.github.io/LWG/lwg-active.html#2926">2926</a></td>
    <td><tt><i>INVOKE</i>(f, t1, t2,... tN)</tt> and <tt><i>INVOKE</i>(f, t1, t2,... tN, R)</tt> are too similar</td>
  </tr>
  <tr>
    <td><a href="http://cplusplus.github.io/LWG/lwg-active.html#2927">2927</a></td>
    <td>Encoding a functor and argument types as a function signature for <tt>is_callable</tt> and <tt>result_of</tt> is fragile</td>
  </tr>
  <tr>
    <td><a href="http://cplusplus.github.io/LWG/lwg-active.html#2928">2928</a></td>
    <td><tt>is_callable</tt> is not a good name</td>
  </tr>
</table> 

<h2><a name="Proposed_resolution"></a>Proposed Resolution</h2>

<p>
At some places below, additional markup of the form
</p>
<blockquote class="note">
<p>
[<i>Drafting notes</i>: whatever &mdash; <i>end drafting notes</i>]
</p>
</blockquote>
<p>
is provided, which is <em>not</em> part of the normative wording, but is solely shown to provide additional information 
to the reader about the rationale of the concrete wording.
</p>

<blockquote class="note" style="border-style:solid">
<span style="color:#C80000;font-weight:bold">
<p>
The below list of suggested changes is split into two halves: List (A) is an enumeration of suggested <em>minimalistic</em> 
wording changes and doesn't touch <tt>result_of</tt>, while list (B) separately lists the <em>additional</em> necessary 
changes when adjustments to <tt>result_of</tt> are considered.
</p>
</span>
</blockquote>

<p>
The proposed wording changes refer to the Standard C++ working draft 
<a href="http://wg21.link/n4640">N4640</a>.
</p>

<blockquote class="note">
<p>
[<i>Drafting notes</i>: Searching for current usages of <tt><i>INVOKE</i></tt>, the following locations are
<em>unaffected</em> by the splitting of <tt><i>INVOKE</i>&lt;R&gt;</tt>:
</p>
<ol>
<li><p>20.5.3.5 [tuple.apply] p1</p></li>
<li><p>20.7.7 [variant.visit] p2+p3</p></li>
<li><p>20.14.3 [func.require] p1</p></li>
<li><p>20.14.4 [func.invoke] p1</p></li>
<li><p>20.14.5.4 [refwrap.invoke] p1</p></li>
<li><p>20.14.10 [func.not_fn] p5+p6</p></li>
<li><p>20.14.11.3 [func.bind.bind] p2+p3+p6</p></li>
<li><p>20.14.12 [func.memfn] p1</p></li>
<li><p>Table 50 &mdash; "Other transformations" [Row for template <tt>result_of</tt>]</p></li>
<li><p>30.3.2.2 [thread.thread.constr] p3+p5</p></li>
<li><p>30.4.6.2 [thread.once.callonce] p1+p2</p></li>
<li><p>30.6.9 [futures.async] p2+(3.1)+(3.2)</p></li>
</ol>
<p>
&mdash; <i>end drafting notes</i>]
</p>
</blockquote>

<ol style="list-style-type:upper-alpha">
<li><p><em>Minimalistic</em> suggestion (without any changes affecting <tt>result_of</tt>):</p>

<ol>
<li><p>Modify 20.14.3 [func.require] as indicated:</p>

<blockquote>
<p>
-2- Define <tt><i>INVOKE</i><ins>&lt;R&gt;</ins>(f, t1, t2, ..., tN<del>, R</del>)</tt> as 
<tt>static_cast&lt;void&gt;(<i>INVOKE</i>(f, t1, t2, ..., tN))</tt> if <tt>R</tt> is
<i>cv</i> <tt>void</tt>, otherwise <tt><i>INVOKE</i>(f, t1, t2, ..., tN)</tt> implicitly converted to <tt>R</tt>.
</p>
</blockquote>
</li>

<li><p>Modify 20.14.11.3 [func.bind.bind] as indicated:</p>

<blockquote>
<pre>
template&lt;class R, class F, class... BoundArgs&gt;
  <i>unspecified</i> bind(F&amp;&amp; f, BoundArgs&amp;&amp;... bound_args);
</pre>
<blockquote>
<p>
[&hellip;]
<p/>
-7- <i>Returns:</i> A forwarding call wrapper <tt>g</tt> (20.14.3 [func.require]). The effect of <tt>g(u<sub>1</sub>, u<sub>2</sub>, 
..., u<sub>M</sub>)</tt> shall be
</p>
<blockquote><pre>
<i>INVOKE</i><ins>&lt;R&gt;</ins>(fd, std::forward&lt;V<sub>1</sub>&gt;(v<sub>1</sub>), std::forward&lt;V<sub>2</sub>&gt;(v<sub>2</sub>), 
  ..., std::forward&lt;V<sub>N</sub>&gt;(v<sub>N</sub>)<del>, R</del>)
</pre></blockquote>
<p>
where [&hellip;]
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 20.14.13.2 [func.wrap.func] as indicated:</p>

<blockquote><p>
-2- A callable type (20.14.2 [func.def]) <tt>F</tt> is <em>Lvalue-Callable</em> for argument types <tt>ArgTypes</tt> and return type 
<tt>R</tt> if the expression <tt><i>INVOKE</i><ins>&lt;R&gt;</ins>(declval&lt;F&amp;&gt;(), 
declval&lt;ArgTypes&gt;()...<del>, R</del>)</tt>, considered as an unevaluated operand (Clause 5 [expr]), is well formed 
(20.14.3 [func.require]).
</p></blockquote>
</li>

<li><p>Modify 20.14.13.2.4 [func.wrap.func.inv] as indicated:</p>

<blockquote>
<pre>
R operator()(ArgTypes... args) const;
</pre>
<blockquote>
<p>
-1- <i>Returns:</i> <tt><i>INVOKE</i><ins>&lt;R&gt;</ins>(f, std::forward&lt;ArgTypes&gt;(args)...<del>, R</del>)</tt> 
(20.14.3 [func.require]), where <tt>f</tt> is the target object (20.14.2 [func.def]) of <tt>*this</tt>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 20.15.2 [meta.type.synop], header <tt>&lt;type_traits&gt;</tt> synopsis, as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting notes</i>: The newly introduced variable template constants are intentionally marked as <tt>inline</tt> to
be consistent with the resolution bullet list (B2) from <a href="http://wg21.link/p0607r0">P0607R0</a> 
"Inline Variables for the Standard Library" which had been preferred by the Committee &mdash; <i>end drafting notes</i>]
</p>
</blockquote>

<blockquote>
<pre>
[&hellip;]
<i>// 20.15.6 [meta.rel], type relations</i>
[&hellip;]

<del>template &lt;class, class R = void&gt; struct is_callable; // not defined
template &lt;class Fn, class... ArgTypes, class R&gt;
struct is_callable&lt;Fn(ArgTypes...), R&gt;;</del>
<ins>template &lt;class Fn, class... ArgTypes&gt; struct is_invocable;
template &lt;class R, class Fn, class... ArgTypes&gt; struct is_invocable_r;</ins>

<del>template &lt;class, class R = void&gt; struct is_nothrow_callable; // not defined
template &lt;class Fn, class... ArgTypes, class R&gt;
struct is_nothrow_callable&lt;Fn(ArgTypes...), R&gt;;</del>
<ins>template &lt;class Fn, class... ArgTypes&gt; struct is_nothrow_invocable;
template &lt;class R, class Fn, class... ArgTypes&gt; struct is_nothrow_invocable_r;</ins>

[&hellip;]

<i>// 20.15.6 [meta.rel], type relations</i>
[&hellip;]
<del>template &lt;class T, class R = void&gt; constexpr bool is_callable_v
  = is_callable&lt;T, R&gt;::value;
template &lt;class T, class R = void&gt; constexpr bool is_nothrow_callable_v
  = is_nothrow_callable&lt;T, R&gt;::value;</del>
<ins>template &lt;class Fn, class... ArgTypes&gt; inline constexpr bool is_invocable_v
  = is_invocable&lt;Fn, ArgTypes...&gt;::value;
template &lt;class R, class Fn, class... ArgTypes&gt; inline constexpr bool is_invocable_r_v
  = is_invocable_r&lt;R, Fn, ArgTypes...&gt;::value;
template &lt;class Fn, class... ArgTypes&gt; inline constexpr bool is_nothrow_invocable_v
  = is_nothrow_invocable&lt;Fn, ArgTypes...&gt;::value;
template &lt;class R, class Fn, class... ArgTypes&gt; inline constexpr bool is_nothrow_invocable_r_v
  = is_nothrow_invocable_r&lt;R, Fn, ArgTypes...&gt;::value;</ins>
[&hellip;]
</pre>
</blockquote>

</li>

<li><p>Modify 20.15.6 [meta.rel], Table 44 &mdash; "Type relationship predicates", as indicated:</p>

<blockquote>
<table border="1">
<caption>Table 44 &mdash; Type relationship predicates</caption>
<tr>
<th align="center">Template</th>
<th align="center">Condition</th>
<th align="center">Comments</th>
</tr>

<tr>
<td colspan="3" align="center">
<tt>[&hellip;]</tt>
</td>
</tr>

<tr>
<td>
<tt>template &lt;class Fn, class...<br/> 
ArgTypes<del>, class R</del>&gt;<br/> 
struct is_<ins>invocable</ins><del>callable&lt;<br/> 
Fn(ArgTypes...), R&gt;</del>;</tt>
</td>
<td>
The expression<br/>
<tt><i>INVOKE</i>(declval&lt;Fn&gt;(),<br/>
declval&lt;ArgTypes&gt;()...<del>,<br/>
R</del>)</tt> is well formed when treated<br/>
as an unevaluated operand
</td>
<td>
<tt>Fn</tt><del>, <tt>R</tt>,</del> and all types in the<br/>
parameter pack <tt>ArgTypes</tt> shall<br/>
be complete types, <i>cv</i> <tt>void</tt>, or<br/>
arrays of unknown bound.
</td>
</tr>

<tr>
<td>
<ins><tt>template &lt;class R, class Fn, class...<br/> 
ArgTypes&gt;<br/> 
struct is_invocable_r;</tt></ins>
</td>
<td>
<ins>The expression<br/>
<tt><i>INVOKE</i>&lt;R&gt;(declval&lt;Fn&gt;(),<br/>
declval&lt;ArgTypes&gt;()...)</tt><br/>
is well formed when treated<br/>
as an unevaluated operand</ins>
</td>
<td>
<ins><tt>Fn</tt>, <tt>R</tt>, and all types in the<br/>
parameter pack <tt>ArgTypes</tt> shall<br/>
be complete types, <i>cv</i> <tt>void</tt>, or<br/>
arrays of unknown bound.</ins>
</td>
</tr>

<tr>
<td>
<tt>template &lt;class Fn, class...<br/> 
ArgTypes<del>, class R</del>&gt;<br/> 
struct is_nothrow_<ins>invocable</ins><del>callable&lt;<br/> 
Fn(ArgTypes...), R&gt;</del>;</tt>
</td>
<td>
<tt>is_<ins>invocable</ins><del>callable</del>_v&lt;<br/>
<ins>Fn, ArgTypes...</ins><del>Fn(ArgTypes...), R</del>&gt;</tt> is<br/>
<tt>true</tt> and the expression<br/>
<tt><i>INVOKE</i>(declval&lt;Fn&gt;(),<br/>
declval&lt;ArgTypes&gt;()...<del>,<br/>
R</del>)</tt> is known not to throw any<br/>
exceptions
</td>
<td>
<tt>Fn</tt><del>, <tt>R</tt>,</del> and all types in the<br/>
parameter pack <tt>ArgTypes</tt> shall<br/>
be complete types, <i>cv</i> <tt>void</tt>, or<br/>
arrays of unknown bound.
</td>
</tr>

<tr>
<td>
<ins><tt>template &lt;class R, class Fn, class...<br/> 
ArgTypes&gt;<br/> 
struct is_nothrow_invocable_r;</tt></ins>
</td>
<td>
<ins><tt>is_invocable_r_v&lt;<br/>
R, Fn, ArgTypes...&gt;</tt> is<br/>
<tt>true</tt> and the expression<br/>
<tt><i>INVOKE&lt;R&gt;</i>(declval&lt;Fn&gt;(),<br/>
declval&lt;ArgTypes&gt;()...)</tt><br/>
is known not to throw any<br/>
exceptions</ins>
</td>
<td>
<ins><tt>Fn</tt>, <tt>R</tt>, and all types in the<br/>
parameter pack <tt>ArgTypes</tt> shall<br/>
be complete types, <i>cv</i> <tt>void</tt>, or<br/>
arrays of unknown bound.</ins>
</td>
</tr>

</table>
</blockquote>
</li>

<li><p>Modify 30.6.10.1 [futures.task.members] as indicated:</p>

<blockquote>
<pre>
template &lt;class F&gt;
packaged_task(F&amp;&amp; f);
template &lt;class F, class Allocator&gt;
packaged_task(allocator_arg_t, const Allocator&amp; a, F&amp;&amp; f);
</pre>
<blockquote>
<p>
-2- <i>Requires:</i> <tt><i>INVOKE</i><ins>&lt;R&gt;</ins>(f, t1, t2, ..., tN<del>, R</del>)</tt>, where <tt>t1, t2, ..., tN</tt> 
are values of the corresponding types in <tt>ArgTypes...</tt>, shall be a valid expression. [&hellip;]
</p>
</blockquote>
<p>
[&hellip;]
</p>
<pre>
void operator()(ArgTypes... args);
</pre>
<blockquote>
<p>
-16- <i>Effects:</i> As if by <tt><i>INVOKE</i><ins>&lt;R&gt;</ins>(f, t1, t2, ..., tN<del>, R</del>)</tt>, where <tt>f</tt> is 
the stored task of <tt>*this</tt> and <tt>t1, t2, ..., tN</tt> are the values in <tt>args...</tt>. [&hellip;]
<p/>
[&hellip;]
</p>
</blockquote>
<pre>
void make_ready_at_thread_exit(ArgTypes... args);
</pre>
<blockquote>
<p>
-19- <i>Effects:</i> As if by <tt><i>INVOKE</i><ins>&lt;R&gt;</ins>(f, t1, t2, ..., tN<del>, R</del>)</tt>, where <tt>f</tt> 
is the stored task and <tt>t1, t2, ..., tN</tt> are the values in <tt>args...</tt>. [&hellip;]
<p/>
[&hellip;]
</p>
</blockquote>
</blockquote>
</li>

</ol>

</li>

<li><p><em>Additional</em> suggestion (solely focussing of changes related to <tt>result_of</tt>):</p>

<ol>
<li><p>Modify 20.14.1 [functional.syn], header <tt>&lt;functional&gt;</tt> synopsis, as indicated:</p>

<blockquote>
<pre>
<i>// 20.14.4 [func.invoke], invoke</i>
template &lt;class F, class... Args&gt;
  <ins>invoke_result_t&lt;F, Args...&gt;</ins><del>result_of_t&lt;F&amp;&amp;(Args&amp;&amp;...)&gt;</del> invoke(F&amp;&amp; f, Args&amp;&amp;... args);
</pre>
</blockquote>

</li>

<li><p>Modify 20.14.4 [func.invoke] as indicated:</p>

<blockquote>
<pre>
template &lt;class F, class... Args&gt;
  <ins>invoke_result_t&lt;F, Args...&gt;</ins><del>result_of_t&lt;F&amp;&amp;(Args&amp;&amp;...)&gt;</del> invoke(F&amp;&amp; f, Args&amp;&amp;... args);
</pre>
</blockquote>

</li>

<li><p>Modify 20.14.5 [refwrap], class template <tt>reference_wrapper</tt> synopsis, as indicated:</p>

<blockquote>
<pre>
[&hellip;]
<i>// invocation</i>
template &lt;class... ArgTypes&gt;
<ins>invoke_result_t&lt;T&amp;, ArgTypes...&gt;</ins>
<del>result_of_t&lt;T&amp;(ArgTypes&amp;&amp;...)&gt;</del>
operator() (ArgTypes&amp;&amp;...) const;
[&hellip;]
</pre>
</blockquote>

</li>

<li><p>Modify 20.14.5.4 [refwrap.invoke] as indicated:</p>

<blockquote>
<pre>
template &lt;class... ArgTypes&gt;
  <ins>invoke_result_t&lt;T&amp;, ArgTypes...&gt;</ins>
  <del>result_of_t&lt;T&amp;(ArgTypes&amp;&amp;...)&gt;</del>
    operator() (ArgTypes&amp;&amp;...) const;
</pre>
</blockquote>

</li>

<li><p>Modify 20.14.10 [func.not_fn], <tt><i>call_wrapper</i></tt> synopsis, as indicated:</p>

<blockquote>
<pre>
template&lt;class... Args&gt;
  auto operator()(Args&amp;&amp;...) &amp;
    -&gt; decltype(!declval&lt;<ins>invoke_result_t&lt;FD&amp;, Args...&gt;</ins><del>result_of_t&lt;FD&amp;(Args&amp;&amp;...)&gt;</del>&gt;());
    
template&lt;class... Args>
  auto operator()(Args&amp;&amp;...) const&amp;
    -&gt; decltype(!declval&lt;<ins>invoke_result_t&lt;const FD&amp;, Args...&gt;</ins><del>result_of_t&lt;const FD&amp;(Args&amp;&amp;...)&gt;</del>&gt;());

template&lt;class... Args&gt;
  auto operator()(Args&amp;&amp;...) &amp;&amp;
    -&gt; decltype(!declval&lt;<ins>invoke_result_t&lt;FD, Args...&gt;</ins><del>result_of_t&lt;FD(Args&amp;&amp;...)&gt;</del>&gt;());

template&lt;class... Args&gt;
  auto operator()(Args&amp;&amp;...) const&amp;&amp;
    -&gt; decltype(!declval&lt;<ins>invoke_result_t&lt;const FD, Args...&gt;</ins><del>result_of_t&lt;const FD(Args&amp;&amp;...)&gt;</del>&gt;());
</pre>
<p>
[&hellip;]
</p>
<pre>
template&lt;class... Args&gt;
  auto operator()(Args&amp;&amp;...) &amp;
    -&gt; decltype(!declval&lt;<ins>invoke_result_t&lt;FD&amp;, Args...&gt;</ins><del>result_of_t&lt;FD&amp;(Args&amp;&amp;...)&gt;</del>&gt;());    
template&lt;class... Args>
  auto operator()(Args&amp;&amp;...) const&amp;
    -&gt; decltype(!declval&lt;<ins>invoke_result_t&lt;const FD&amp;, Args...&gt;</ins><del>result_of_t&lt;const FD&amp;(Args&amp;&amp;...)&gt;</del>&gt;());
</pre>
<blockquote>
<p>
-5- [&hellip;]
</p>
</blockquote>
<pre>
template&lt;class... Args&gt;
  auto operator()(Args&amp;&amp;...) &amp;&amp;
    -&gt; decltype(!declval&lt;<ins>invoke_result_t&lt;FD, Args...&gt;</ins><del>result_of_t&lt;FD(Args&amp;&amp;...)&gt;</del>&gt;());
template&lt;class... Args&gt;
  auto operator()(Args&amp;&amp;...) const&amp;&amp;
    -&gt; decltype(!declval&lt;<ins>invoke_result_t&lt;const FD, Args...&gt;</ins><del>result_of_t&lt;const FD(Args&amp;&amp;...)&gt;</del>&gt;());
</pre>
<blockquote>
<p>
-6- [&hellip;]
</p>
</blockquote>
</blockquote>

</li>

<li><p>Modify 20.14.11.3 [func.bind.bind] as indicated:</p>

<blockquote>
<pre>
template&lt;class R, class F, class... BoundArgs&gt;
  <i>unspecified</i> bind(F&amp;&amp; f, BoundArgs&amp;&amp;... bound_args);
</pre>
<blockquote>
<p>
[&hellip;]
</p>
</blockquote>
<p>
-10- The values of the <em>bound arguments</em> [&hellip;] :
</p>
<ol style="list-style-type: none">
<li><p>(10.1) &mdash; [&hellip;]</p></li>
<li><p>(10.2) &mdash; if the value of <tt>is_bind_expression_v&lt;TD<sub><i>i</i></sub>&gt;</tt> is <tt>true</tt>, 
the argument is <tt>td<sub><i>i</i></sub>(std::forward&lt;U<sub><i>j</i></sub>&gt;(u<sub><i>j</i></sub>)...)</tt>
and its type <tt>V<sub><i>i</i></sub></tt> is 
<ins><tt>invoke_result_t&lt;TD<sub><i>i</i></sub> <i>cv</i> &amp;, U<sub><i>j</i></sub>...&gt;&amp;&amp;</tt></ins>
<del><tt>result_of_t&lt;TD<sub><i>i</i></sub> <i>cv</i> &amp; (U<sub><i>j</i></sub>&amp;&amp;...)&gt;&amp;&amp;</tt></del>;</p></li>
<li><p>(10.3) &mdash; [&hellip;]</p></li>
</ol>
</blockquote>

</li>

<li><p>Modify 20.15.2 [meta.type.synop], header <tt>&lt;type_traits&gt;</tt> synopsis, as indicated:</p>

<blockquote class="note">
[<i>Drafting notes</i>: The changes below additionally fix an existing inconsistent usage of class-key <tt>class</tt>
instead of <tt>struct</tt>. Albeit both are equivalent as of the letters of the core language, there are compilers
that mangle both forms differently. &mdash; <i>end drafting notes</i>]
</blockquote>

<blockquote>
<pre>
<i>// 20.15.7.6 [meta.trans.other], other transformations</i>
[&hellip;]
<del>template &lt;class&gt; class result_of; <i>// not defined</i>
template &lt;class F, class... ArgTypes&gt; class result_of&lt;F(ArgTypes...)&gt;;</del>
<ins>template &lt;class Fn, class... ArgTypes&gt; struct invoke_result;</ins>
[&hellip;]

<i>// 20.15.7.6 [meta.trans.other], other transformations</i>
[&hellip;]
<del>template &lt;class T&gt;
  using result_of_t = typename result_of&lt;T&gt;::type;</del>
<ins>template &lt;class Fn, class... ArgTypes&gt;
  using invoke_result_t = typename invoke_result&lt;Fn, ArgTypes...&gt;::type;</ins>
[&hellip;]
</pre>
</blockquote>
</li>

<li><p>Modify 20.15.7.6 [meta.trans.other], Table 50 &mdash; "Other transformations" and the following example, as indicated:</p>

<blockquote>
<table border="1">
<caption>Table 50 &mdash; Other transformations</caption>
<tr>
<th align="center">Template</th>
<th align="center">Comments</th>
</tr>

<tr>
<td colspan="3" align="center">
<tt>[&hellip;]</tt>
</td>
</tr>

<tr>
<td>
<tt>template &lt;class Fn,<br/> 
class... ArgTypes&gt;<br/> 
struct <ins>invoke_result</ins><del>result_of&lt;<br/> 
Fn(ArgTypes...)&gt;</del>;</tt>
</td>
<td>
If the expression <tt><i>INVOKE</i>(declval&lt;Fn&gt;(),<br/>
declval&lt;ArgTypes&gt;()...)</tt> is well formed when treated as an<br/>
unevaluated operand (Clause 5 [expr]), the member typedef type shall<br/>
name the type <tt>decltype(<i>INVOKE</i>(declval&lt;Fn&gt;(),<br/>
declval&lt;ArgTypes&gt;()...))</tt>; otherwise, there shall be no member<br/>
type. Access checking is performed as if in a context unrelated to <tt>Fn</tt><br/>
and <tt>ArgTypes</tt>.<br/> 
[&hellip;]<br/>
<i>Requires:</i> <tt>Fn</tt> and all types in the parameter pack <tt>ArgTypes</tt> shall be<br/>
complete types, <i>cv</i> <tt>void</tt>, or arrays of unknown bound.
</td>
</tr>

</table>
<p>
[&hellip;]
<p/>
-5- [<i>Example:</i> Given these definitions:
</p>
<pre>
using PF1 = bool (&amp;)();
using PF2 = short (*)(long);

struct S {
  operator PF2() const;
  double operator()(char, int&);
  void fn(long) const;
  char data;
};

using PMF = void (S::*)(long) const;
using PMD = char S::*;
</pre>
<p>
the following assertions will hold:
</p>
<pre>
static_assert(is_same_v&lt;<ins>invoke_result_t&lt;S, int&gt;</ins><del>result_of_t&lt;S(int)&gt;</del>, short&gt;, "Error!");
static_assert(is_same_v&lt;<ins>invoke_result_t&lt;S&amp;, unsigned char, int&amp;&gt;</ins><del>result_of_t&lt;S&amp;(unsigned char, int&amp;)&gt;</del>, double&gt;, "Error!");
static_assert(is_same_v&lt;<ins>invoke_result_t&lt;PF1&gt;</ins><del>result_of_t&lt;PF1()&gt;</del>, bool&gt;, "Error!");
static_assert(is_same_v&lt;<ins>invoke_result_t&lt;PMF, unique_ptr&lt;S&gt;, int&gt;</ins><del>result_of_t&lt;PMF(unique_ptr&lt;S&gt;, int)&gt;</del>, void&gt;, "Error!");
static_assert(is_same_v&lt;<ins>invoke_result_t&lt;PMD, S&gt;</ins><del>result_of_t&lt;PMD(S)&gt;</del>, char&amp;&amp;&gt;, "Error!");
static_assert(is_same_v&lt;<ins>invoke_result_t&lt;PMD, const S*&gt;</ins><del>result_of_t&lt;PMD(const S*)&gt;</del>, const char&amp;&gt;, "Error!");
</pre>
<p>
&mdash; <i>end example</i>]
</p>
</blockquote>
</li>

<li><p>Modify 30.6.2 [future.syn], header <tt>&lt;future&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
[&hellip;]
template &lt;class F, class... Args&gt;
  future&lt;<ins>invoke_result_t&lt;decay_t&lt;F&gt;, decay_t&lt;Args&gt;...&gt;</ins><del>result_of_t&lt;decay_t&lt;F&gt;(decay_t&lt;Args&gt;...)&gt;</del>&gt;
  async(F&amp;&amp; f, Args&amp;&amp;... args);
template &lt;class F, class... Args&gt;
  future&lt;<ins>invoke_result_t&lt;decay_t&lt;F&gt;, decay_t&lt;Args&gt;...&gt;</ins><del>result_of_t&lt;decay_t&lt;F&gt;(decay_t&lt;Args&gt;...)&gt;</del>&gt;
  async(launch policy, F&amp;&amp; f, Args&amp;&amp;... args);
</pre></blockquote>
</li>

<li><p>Modify 30.6.9 [futures.async] as indicated:</p>

<blockquote>
<pre>
template &lt;class F, class... Args&gt;
  future&lt;<ins>invoke_result_t&lt;decay_t&lt;F&gt;, decay_t&lt;Args&gt;...&gt;</ins><del>result_of_t&lt;decay_t&lt;F&gt;(decay_t&lt;Args&gt;...)&gt;</del>&gt;
  async(F&amp;&amp; f, Args&amp;&amp;... args);
template &lt;class F, class... Args&gt;
  future&lt;<ins>invoke_result_t&lt;decay_t&lt;F&gt;, decay_t&lt;Args&gt;...&gt;</ins><del>result_of_t&lt;decay_t&lt;F&gt;(decay_t&lt;Args&gt;...)&gt;</del>&gt;
  async(launch policy, F&amp;&amp; f, Args&amp;&amp;... args);
</pre>
<blockquote>
<p>
-2- [&hellip;]
<p/>
[&hellip;]
<p/>
-4- <i>Returns:</i> An object of type <tt>future&lt;<ins>invoke_result_t&lt;decay_t&lt;F&gt;, decay_t&lt;Args&gt;...&gt;</ins><del>result_of_t&lt;decay_t&lt;F&gt;(decay_t&lt;Args&gt;...)&gt;</del>&gt;</tt> that refers to
the shared state created by this call to <tt>async</tt>. [&hellip;]
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify D.11 [depr.meta.types], "Deprecated type traits" as indicated:</p>

<blockquote class="note">
[<i>Drafting notes</i>: The changes below additionally fix an existing inconsistent usage of class-key <tt>class</tt>
instead of <tt>struct</tt>, see above.</i>]
</blockquote>

<blockquote>
<p>
-1- The header <tt>&lt;type_traits&gt;</tt> has the following addition:
</p>
<blockquote>
<pre>
namespace std {
  template &lt;class T&gt; struct is_literal_type;
  template &lt;class T&gt; constexpr bool is_literal_type_v = is_literal_type&lt;T&gt;::value;
  <ins>template &lt;class&gt; struct result_of; <i>// not defined</i>
  template &lt;class Fn, class... ArgTypes&gt; struct result_of&lt;Fn(ArgTypes...)&gt;;
  template &lt;class T&gt; using result_of_t = typename result_of&lt;T&gt;::type;</ins>
}
</pre>
</blockquote>
<p>
-2- <i>Requires:</i> <ins>For <tt>is_literal_type</tt>,</ins> <tt>remove_all_extents_t&lt;T&gt;</tt> shall be a 
complete type or <i>cv</i> <tt>void</tt>. <ins>For <tt>result_of&lt;Fn(ArgTypes...)&gt;</tt>, <tt>Fn</tt> and all types 
in the parameter pack <tt>ArgTypes</tt> shall be complete types, <i>cv</i> <tt>void</tt>, or arrays of unknown bound.</ins>
<p/>
-3- <i>Effects:</i> <tt>is_literal_type</tt> has a base-characteristic of <tt>true_type</tt> 
if <tt>T</tt> is a literal type (3.9), and a base-characteristic of <tt>false_type</tt> otherwise.
<ins>The partial specialization <tt>result_of&lt;Fn(ArgTypes...)&gt;</tt> is a <tt>TransformationTrait</tt> whose 
member typedef <tt>type</tt> shall be defined if and only <tt>invoke_result&lt;Fn, ArgTypes...&gt;::type</tt> is defined. 
If <tt>type</tt> is defined, it shall name the same type as <tt>invoke_result_t&lt;Fn, ArgTypes...&gt;</tt>.</ins>
</p>
</blockquote>
</li>
</ol>

</li>
</ol>

<h2><a name="FeatureMacro"></a>Feature-testing Macro</h2>
<p>
For the purposes of SG10, this paper recommends to change the originally suggested macro name <tt>__cpp_lib_is_callable</tt>
to <tt>__cpp_lib_is_invocable</tt>.
</p>

</body></html>