<!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>Implicit conversion traits and utility functions</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: P0758R0<br>
Date: 2017-07-30<br>
Audience: Library Evolution Working Group, Library Working Group<br>
Author: Daniel Kr&uuml;gler<br>
Reply-to: <a href="mailto:daniel.kruegler@gmail.com">Daniel Kr&uuml;gler</a>
</address>
<hr>
<h1 style="text-align: center;">Implicit conversion traits and utility functions</h1>

<ul>
<li><a href="#Intro">Introduction</a></li>
<li><a href="#Discussion">Discussion</a></li>
<li><a href="#ProposalCandidates">Proposal Candidates</a></li>
<li><a href="#Issues_Resolved">Resolved Issues</a></li>
<li><a href="#Proposed_resolution">Proposed Resolution [<em>Exposition</em>]</a></li>
<li><a href="#FeatureMacros">Feature-testing Macros</a></li>
<li><a href="#Bibliography">Bibliography</a></li>
<li><a href="#Appendix">Partial Sample Implementation</a></li>
</ul>

<h2><a name="Intro"></a>Introduction</h2>
<p>
This is an initial paper that focuses on some missing traits describing <em>implicit conversions</em> &mdash; 
related to the existing <tt>is_convertible</tt> trait &mdash; and on some utility function templates
useful in that context of such conversions. 
<p/>
Albeit this proposal <em>could</em> have been a rather minimalistic proposal by suggesting only a single new trait
<tt>is_nothrow_convertible</tt>, the author prefers to do it the harder way and to explore to some extend a set 
of reasonable utility additions around the same main topic, asking the committee for feedback to refine it in
a second step.
<p/>
By means of these suggested new facilities, this paper attempts to resolve the existing library issues 
<a href="http://wg21.link/lwg2040">LWG 2040</a> and <a href="http://wg21.link/lwg2999">LWG 2999</a> and
to improve some other Standard Library specifications.
</p>
<blockquote><pre>
</pre></blockquote>
<p>
</p>

<h2><a name="Discussion"></a>Discussion</h2>
<p>
The <tt>is_convertible</tt> trait is a quite interesting trait, because it describes <b>implicit 
conversions</b> (See also <sup><a href="#bib-P0705R0">1</a></sup> for a survey about implicit and explicit
conversions). From a core language point of view, a different angle of looking at implicit conversions is to 
talk about <b>copy initialization</b>, because both meet each other in a variable definition 
of the form
</p>
<blockquote><pre>
T t = e;
</pre></blockquote>
<p>
Other initialization contexts that are described by <b>copy initialization</b> are aggregate member initialization,
function return, and argument passing, to name just a few of them, which shows (a) the ubiquitous nature of implicit 
conversions and (b) the nearness to construction semantics, the latter being described in the most general (parenthesized) direct-initialization form by the <tt>is_constructible</tt> trait.
<p/>
With these relations in mind, it seems rather unfortunate that the historic trait adjustment proposal
<a href="http://wg21.link/n3142">N3142</a> omitted a similar treatment of <em>triviality</em> and <em>nothrow</em>
aspects of the <tt>is_convertible</tt> trait. 
<p/>
Therefore, this proposal suggests to add two new type traits <tt>std::is_nothrow_convertible&lt;From, To&gt;</tt> and
<tt>std::is_trivially_convertible&lt;From, To&gt;</tt> to the header <tt>&lt;type_traits&gt;</tt>. In addition to that, 
this paper suggests to replace the existing pseudofunction <tt><i>DECAY_COPY</i></tt> by a real library template 
<tt>std::decay_copy</tt> added to header <tt>&lt;utility&gt;</tt> and a complete new conversion function 
<tt>std::implicit_cast</tt> added to header <tt>&lt;utility&gt;</tt> as well.
<p>
<b>Albeit this paper provides a <a href="#Proposed_resolution">Proposed Resolution</a> section, this one
should be considered as expositional for the level of this initial paper revision to provide a rough picture of the 
intended amount of wording changes!</b>  
</p>

<h2><a name="ProposalCandidates"></a>Proposal Candidates</h2>
<h3><a name="ProposalCandidates.is_nothrow_convertible"></a>1. <tt>is_nothrow_convertible</tt></h3>
<p>
The <tt>is_nothrow_convertible</tt> trait 
</p>
<blockquote><pre>
template &lt;class From, class To&gt; 
struct is_nothrow_convertible;
</pre></blockquote>
<p>
is presumably one of the most often asked for traits related to <tt>is_convertible</tt>.
One of the earliest official notes of the lack of that feature occurred during the publication of the
<a href="#bib-n3255">N3255</a> proposal that shortly before the C++11 finalization attempted to standardize a new Standard
Library function template <tt>decay_copy</tt> as replacement for the existing <tt><i>DECAY_COPY</i></tt> pseudo-function.
Among other reasons (especially the lateness of the feature request), this proposal failed, because it couldn't provide
the correct conditional exception specification, concluding:
</p>
<blockquote><p> 
"What we would need is <tt>std::is_nothrow_convertible</tt>."
</p></blockquote>
<p>
Shortly after C++11 standardization, <a href="http://wg21.link/lwg2040">LWG 2040</a> was filed requesting the addition
of <tt>is_nothrow_convertible</tt> and <tt>is_trivially_convertible</tt>, but is since then in a kind of zombie state.
<p/>
There are several concrete use-cases for the <tt>is_nothrow_convertible</tt> trait:
</p>
<ol>
<li><p>
It could be used to specify the correct <tt>noexcept</tt> expression for a <tt>decay_copy</tt> replacement template
for <tt><i>DECAY_COPY</i></tt>, which would resolve one important aspect of <a href="http://wg21.link/lwg2999">LWG 2999</a>.
</p></li>
<li><p>
It could be used to restore the valueable (now conditionally) <tt>noexcept</tt> specification for several 
non-throwing <tt>basic_string</tt> functions that had been "<tt>string_view</tt>"-ified, as described by
<a href="http://wg21.link/lwg2946">LWG 2946</a>. As example consider adjusting the currently suggested wording changes for
the following <tt>find</tt> signature:
</p>
<blockquote>
<pre>
<ins>template &lt;class T&gt;</ins>
size_type find(<del>basic_string_view&lt;charT, traits&gt; sv</del><ins>const T&amp; t</ins>, size_type pos = 0) const noexcept<ins>(<i>see below</i>)</ins>;
</pre>
<blockquote>
<p>
-1- <i>Effects:</i> <ins>Creates a variable, <tt>sv</tt>, as if by <tt>basic_string_view&lt;charT, traits&gt; sv = t;</tt> 
and then d</ins><del>D</del>etermines the lowest position <tt>xpos</tt>, if possible, such that both of the following conditions
hold: [&hellip;]
<p/>
-2- <i>Returns:</i> <tt>xpos</tt> if the function can determine such a value for <tt>xpos</tt>. Otherwise, returns <tt>npos</tt>.
<p/>
<ins>-?- <i>Remarks:</i> This function shall not participate in overload resolution unless 
<tt>is_convertible_v&lt;const T&amp;, basic_string_view&lt;charT, traits&gt;&gt;</tt> is <tt>true</tt> and 
<tt>is_convertible_v&lt;const T&amp;, const charT*&gt;</tt> is <tt>false</tt>. The expression inside <tt>noexcept</tt> 
is equivalent to:</ins>
</p>
<blockquote><pre>
<ins>is_nothrow_convertible_v&lt;const T&amp;, basic_string_view&lt;charT, traits&gt;&gt;</ins>
</pre></blockquote>
</blockquote>
</blockquote>
</li>
<li><p>
It could be used to define exception-correct &mdash; either by user-code or by the Standard Library &mdash; a
fundamental <tt>implicit_cast</tt> utility function, see below.
</p></li>
</ol>

<h3><a name="ProposalCandidates.is_trivially_convertible"></a>2. <tt>is_trivially_convertible</tt></h3>
<p>
The <tt>is_trivially_convertible</tt> trait answers the question whether during an implicit conversion as
specified by <tt>is_convertible</tt>, <em>only</em> trivial functions are involved: 
</p>
<blockquote><pre>
template &lt;class From, class To&gt; 
struct is_trivially_convertible;
</pre></blockquote>
<p>
This trait requires compiler-support and it should therefore be sufficiently motivated. The 
<tt>is_convertible&lt;From, To&gt;</tt> semantics has very much similarities to 
<tt>is_constructible&lt;To, From&gt;</tt>, but it applies in cases where <tt>is_constructible</tt> doesn't work, 
for example the semantics of parameter passing or function return or aggregate member initialization.
All of these situations can take advantage of reflecting upon trivial conversions. 
<p/>
For example, one could conditionally decide for a function parameter policy based on "by-value" or "by-reference" by
considering whether the relevant initialization (either homogenous or heterogenous) involves only trivial operations 
or not. 
<p/>
The author asserts that once you have implemented a binary <tt>is_trivially_constructible</tt> intrinsic,
you get the <tt>is_trivially_convertible</tt> intrinsic for a very cheap price, since the essential work is the same, 
except that you consider the initialization using implicit conversions instead of explicit ones.
There are possible other candidates of "primitive" operations that would like to take advantage of a
corresponding <tt>is_trivially_xxx</tt> traits, too, but it seems that implicit conversions are so widespread
and in regard to their fundamental role comparable to <tt>is_constructible</tt> semantics that the lack of 
<tt>is_trivially_convertible</tt> feels a bit like a hole in the trait system.
</p>

<h3><a name="ProposalCandidates.decay_copy"></a>3. <tt>decay_copy</tt></h3>
<p>
The <tt>decay_copy</tt> function template can be written essentially as follows:
</p>
<blockquote><pre>
template &lt;class T&gt;
constexpr decay_t&lt;T&gt; decay_copy(T&amp;&amp; v) noexcept(is_nothrow_convertible_v&lt;T, decay_t&lt;T&gt;&gt;) 
{
  return std::forward&lt;T&gt;(v);
}
</pre></blockquote>
<p>
It describes the implicit conversion of an object (or function) of type <tt>T</tt> to its decayed object form, 
that is, references and <i>cv</i> qualifiers are removed (in the "correct" order) and array/function decay is 
performed (if possible). This kind of functionality it basically everywhere needed, where you want to prevent dangling 
references by introducing an independent object of the given type with the same "value" as its source. 
<p/>
In particular, the Standard Library uses this kind of semantics when specifying the construction of a 
<tt>std::thread</tt> and <tt>std::async</tt> to copy the functor and its possibly bound arguments, because in 
both cases the actual usage of these objects happens in a different thread from the caller thread. In the absence 
of a "real" <tt>decay_copy</tt> function, the library currently uses an exposition-only pseudo-function 
<tt><i>DECAY_COPY</i></tt> with the semantics of a function template as shown above, except that it doesn't 
have an exception specification and does not support <tt>constexpr</tt>.
<p/>
It is not required to specify a function template <tt>decay_copy</tt> <em>including</em> a conditional
<tt>noexcept</tt> specifier, but it would be very advantageous for such a primitive operation.
<p/>
One particular appealing characteristics of <tt>decay_copy</tt> is, that it is hard to use it wrong. This is so,
because this function <em>never</em> returns references, so the risk of dangling references is reduced to the
set of broken types <tt>T</tt> where even the construction of <tt>decay_t&lt;T&gt;</tt> would lead to an internal
dangling reference.
</p>

<h3><a name="ProposalCandidates.implicit_cast"></a>4. <tt>implicit_cast</tt></h3>
<p>
The <tt>implicit_cast</tt> function template can be written essentially as follows:
</p>
<blockquote><pre>
template &lt;class T, class U&gt;
constexpr T implicit_cast(U&amp;&amp; u) noexcept(is_nothrow_convertible_v&lt;U, T&gt;) 
{
  return std::forward&lt;U&gt;(u);
}
</pre></blockquote>
<p>
It can be used whereever an implicit conversion should be part of a possibly multi-step operation. One can consider
<tt>implicit_cast</tt> as a more general function than <tt>decay_copy</tt>, because we could replace a call of
<tt>decay_copy(t)</tt> by <tt>implicit_cast&lt;decay_t&lt;decltype(t)&gt;&gt;(t)</tt>, but this relation would 
normally not be taking advantage of in real-world code, because calling <tt>decay_copy(t)</tt> directly is much 
more intuitive to write. Just to give a usage example, let's look at the following line of the specification of
<a href="http://wg21.link/lwg2993">LWG 2993</a>:
</p>
<blockquote><p>
<ins>-?- <i>Effects:</i> Creates a variable <tt>r</tt> as if by <tt>T&amp; r = std::forward&lt;U&gt;(u)</tt>, then constructs a
<tt>reference_wrapper</tt> object that stores a reference to <tt>r</tt>.</ins>
</p></blockquote>
<p>
which could be rewritten to
</p>
<blockquote><p>
<ins>-?- <i>Effects:</i> Constructs a <tt>reference_wrapper</tt> object that stores a reference to 
<tt>implicit_cast&lt;T&amp;&gt;(std::forward&lt;U&gt;(u))</tt>.</ins>
</p></blockquote>
<p>
In the particular case of <tt>implicit_cast</tt>, some bikeshedding smell is in the air, another naming
candidates could be <tt>implicit_convert</tt>, for example. But according to the opinion of the author, the
term <tt>implicit_cast</tt> is very popular and most public discussions of this function template has the here
discussed semantics or very near to it. Among other examples, the Boost library provides a similar (albeit not
identical) <a href="http://www.boost.org/doc/libs/1_64_0/boost/implicit_cast.hpp"><tt>implicit_cast</tt> template</a>.
<p/>
The differences of both definitions are that the Boost form of <tt>implicit_cast</tt> enforces that the actual 
conversion to the target type <tt>T</tt> happens on the <em>function argument</em> side instead of within the 
function body suggested by the form shown above. This difference is relevant when considering the semantics of
reference binding and of copy-elision.
</p>
<ol>
<li><p>If a conversion results in a reference target type that binds to a prvalue source, the danger of a 
dangling reference exists. In the Boost form, the temporary bound to the reference parameter of <tt>implicit_cast</tt>
persists until the completion of the full-expression containing the call, while in the form shown above
the temporary is destroyed at the end of the full-expression in the return statement.</p></li>
<li><p>If a conversion is performed where the target type is non-copyable and non-movable, the Boost form would
make the code ill-formed, because there is no way for the compiler to perform copy-elision of the function argument
that is returned by the function, but the above shown form will support non-copyable/non-movable types.</p></li>
<li><p>If the conversion throws an exception, a correspondingly <tt>noexcept</tt> specification based on
<tt>is_nothrow_convertible</tt> would correctly describe the exception behaviour of <tt>implicit_cast</tt>
only in the above presented form of <tt>implicit_cast</tt>, because for the Boost form the conversion happens
during function parameter initialization, which is excluded from what an exception specification describes. 
So the Boost form actually consists of two steps: The function
parameter initialization and the initialization of the return value by the function argument. Only the second
step would normally be described by an exception specification.</p></li>
</ol>
<p>
Another way of looking at the problem of the possibility to produce dangling references is by comparing the behaviour
of <tt>implicit_cast</tt> with that of a <tt>std::function</tt> instance that would return a reference in situations
described in <a href="http://wg21.link/lwg2813">LWG 2813 ("<tt>std::function</tt> should not return dangling references")</a>
or in similar situations directly applied to <tt>std::invoke</tt> or <tt><i>INVOKE</i></tt>.
<p/>
The author believes that generally the form of <tt>implicit_cast</tt> shown above is preferable over the Boost variant,
assuming we can make its usage a bit safer for certain cases involving returning references. As the existing discussion 
of LWG <a href="http://wg21.link/lwg2813">2813</a> shows, this is a much wider spread problem not specifically restricted 
to <tt>implicit_cast</tt>. There are basically two possible approaches to fix the dangling reference problem:
</p>
<ol>
<li><p>Attempt to define some conversion restrictions that would SFINAE out a library function template 
<tt>implicit_cast</tt>, similar to the work in progress for LWG <a href="http://wg21.link/lwg2813">2813</a>.</p></li>
<li><p>Define <tt>implicit_cast</tt> not as a libray function template, but as a core language <em>type conversion 
operator</em> (such as <tt>static_cast</tt>). In such a case, any bound object to a reference would be still valid
at the point, where the target variable has been initialized. In this case the operator presumably requires
a different name, since public utility templates named <tt>implicit_cast</tt> are quite common.</p></li>
</ol>
<p>
The author would like to gather feedback from the committee regarding the preferred directions for <tt>implicit_cast</tt>.
</p>

<h2><a name="Issues_Resolved"></a>Resolved Issues</h2>
<p>
If either of the proposed resolutions will 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://wg21.link/lwg2040">2040</a></td>
    <td>Missing type traits related to <tt>is_convertible</tt></td>
  </tr>
  <tr>
    <td><a href="http://wg21.link/lwg2999">2999</a></td>
    <td>&sect;[thread.decaycopy] issue</td>
  </tr>
</table> 

<h2><a name="Proposed_resolution"></a>Proposed resolution [<em>Exposition</em>]</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>

<p>
The proposed wording changes refer in all cases to <a href="http://wg21.link/n4659">N4659</a>.
</p>

<ol>
<li><p>Change 23.2.1 [utility.syn], header <tt>&lt;utility&gt;</tt> synopsis, as indicated:</p>

<blockquote>
<pre>
[&hellip;]
<i>// 23.2.5 [forward], forward/move</i>
template &lt;class T&gt;
  constexpr T&amp;&amp; forward(remove_reference_t&lt;T&gt;&amp; t) noexcept;
template &lt;class T&gt;
  constexpr T&amp;&amp; forward(remove_reference_t&lt;T&gt;&amp;&amp; t) noexcept;
template &lt;class T&gt;
constexpr remove_reference_t&lt;T&gt;&amp;&amp; move(T&amp;&amp;) noexcept;
template &lt;class T&gt;
  constexpr conditional_t&lt;
      !is_nothrow_move_constructible_v&lt;T&gt; &amp;&amp; is_copy_constructible_v&lt;T&gt;, const T&amp;, T&amp;&amp;&gt;
    move_if_noexcept(T&amp; x) noexcept;
<ins>template &lt;class T&gt;
  constexpr decay_t&lt;T&gt; decay_copy(T&amp;&amp; v) noexcept(is_nothrow_convertible_v&lt;T, decay_t&lt;T&gt;&gt;);</ins>
<ins>template &lt;class T, class U&gt;
  constexpr T implicit_cast(U&amp;&amp; u) noexcept(is_nothrow_convertible_v&lt;U, T&gt;);</ins>
</pre>
</blockquote>
</li>

<li><p>At the end of 23.2.5 [forward] add the following series of paragraphs:</p>

<blockquote>
<pre>
<ins>template &lt;class T&gt;
  constexpr decay_t&lt;T&gt; decay_copy(T&amp;&amp; v) noexcept(is_nothrow_convertible_v&lt;T, decay_t&lt;T&gt;&gt;);</ins>
</pre>
<blockquote>
<p>
<ins>-?- <i>Effects:</i> Equivalent to: <tt>return std::forward&lt;T&gt;(v);</tt></ins>
<p/>
<ins>-?- <i>Remarks:</i> This function shall not participate in overload resolution unless 
<tt>is_convertible_v&lt;T, decay_t&lt;T&gt;&gt;</tt> is <tt>true</tt>. [<i>Note:</i> See 33.3.2.2 [thread.thread.constr] 
and 33.6.9 [futures.async] for examples of use. &mdash; <i>end note</i>]</ins>
</p>
</blockquote>

<blockquote class="note">
<p>
[<i>Drafting note:</i> Below we use the more general term <em>reference-compatible with</em> instead of 
<em>reference-related to</em>, because <tt>implicit_cast</tt> can also be used to convert "<tt>noexcept</tt>
function to "function" &mdash; <i>end drafting note</i>]
</p>
</blockquote>

<pre>
<ins>template &lt;class T, class U&gt;
  constexpr T implicit_cast(U&amp;&amp; u) noexcept(is_nothrow_convertible_v&lt;U, T&gt;);</ins>
</pre>
<blockquote>
<p>
<ins>-?- <i>Effects:</i> Equivalent to: <tt>return std::forward&lt;U&gt;(u);</tt></ins>
<p/>
<ins>-?- <i>Remarks:</i> Let <tt><i>V</i></tt> be the type <tt>remove_reference_t&lt;U&gt;</tt>. This function 
shall not participate in overload resolution unless</ins>
<ul>
<li><p><ins><tt>is_convertible_v&lt;U, T&gt;</tt> is <tt>true</tt>, and</ins></p></li>
<li><p><ins>If <tt>T</tt> is type "reference to <tt>S</tt>", <tt><i>V</i></tt> is a class type or <tt>S</tt> is 
reference-compatible (11.6.3 [dcl.init.ref]) with <tt><i>V</i></tt>.</ins></p></li>
</ul> 
</p>
</blockquote>
</blockquote>

</li>

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

<blockquote>
<pre>
namespace std {
  [&hellip;]
  <i>// 23.15.6 [meta.rel], type relations</i>
  template &lt;class T, class U&gt; struct is_same;
  template &lt;class Base, class Derived&gt; struct is_base_of;
  template &lt;class From, class To&gt; struct is_convertible;
  <ins>template &lt;class From, class To&gt; struct is_trivially_convertible;</ins>
  <ins>template &lt;class From, class To&gt; struct is_nothrow_convertible;</ins>
  [&hellip;]
  
  <i>// 23.15.6 [meta.rel], type relations</i>
  template &lt;class T, class UGt; inline constexpr bool is_same_v
    = is_same&lt;T, U&gt;::value;
  template &lt;class Base, class Derived&gt; inline constexpr bool is_base_of_v
    = is_base_of&lt;Base, Derived&gt;::value;
  template &lt;class From, class To&gt; inline constexpr bool is_convertible_v
    = is_convertible&lt;From, To&gt;::value;
  <ins>template &lt;class From, class To&gt; inline constexpr bool is_trivially_convertible_v
    = is_trivially_convertible&lt;From, To&gt;::value;</ins>
  <ins>template &lt;class From, class To&gt; inline constexpr bool is_nothrow_convertible_v
    = is_nothrow_convertible&lt;From, To&gt;::value;</ins>
  [&hellip;]
}
</pre>
</blockquote>
</li>

<li><p>Change 23.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>Template</th>
<th>Condition</th>
<th>Comments</th>
</tr>

<tr>
<td colspan="3" style="text-align:center;">&hellip;</td> 
</tr>

<tr>
<td><tt>template &lt;class From, class To&gt;<br/>
struct is_convertible;</tt></td>
<td><i>see below</i></td>
<td><tt>From</tt> and <tt>To</tt> shall be complete<br/>
types, arrays of unknown<br/>
bound, or <i>cv</i> <tt>void</tt> types.</td>
</tr>

<tr>
<td><ins><tt>template &lt;class From, class To&gt;<br/>
struct is_trivially_convertible;</tt></ins></td>
<td><ins><tt>is_convertible_v&lt;From, To&gt;</tt><br/>
is <tt>true</tt> and the<br/>
conversion, as defined by<br/>
<tt>is_convertible</tt>, is known<br/>
to call no operation that is<br/>
not trivial ([basic.types], [special]).</ins></td>
<td><ins><tt>From</tt> and <tt>To</tt> shall be complete<br/>
types, arrays of unknown<br/>
bound, or <i>cv</i> <tt>void</tt> types.</ins></td>
</tr>

<tr>
<td><ins><tt>template &lt;class From, class To&gt;<br/>
struct is_nothrow_convertible;</tt></ins></td>
<td><ins><tt>is_convertible_v&lt;From, To&gt;</tt><br/>
is <tt>true</tt> and the<br/>
conversion, as defined by<br/>
<tt>is_convertible</tt>, is known<br/>
not to throw any<br/>
exceptions ([expr.unary.noexcept]).</ins></td>
<td><ins><tt>From</tt> and <tt>To</tt> shall be complete<br/>
types, arrays of unknown<br/>
bound, or <i>cv</i> <tt>void</tt> types.</ins></td>
</tr>

<tr>
<td colspan="3" style="text-align:center;">&hellip;</td> 
</tr>

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


<li><p>Remove the complete sub-clause 33.2.6 [thread.decaycopy] as indicated:</p>

<p>
<del><b>33.2.6 <tt>decay_copy</tt> [thread.decaycopy]</b></del>
</p>
<blockquote>
<p>
<del>In several places in this Clause the operation <tt><i>DECAY_COPY</i>(x)</tt> is used. All such uses mean 
call the function <tt>decay_copy(x)</tt> and use the result, where <tt>decay_copy</tt> is defined as follows:</del>
</p>
<blockquote><pre>
<del>template &lt;class T&gt; decay_t&lt;T&gt; decay_copy(T&amp;&amp; v)
  { return std::forward&lt;T&gt;(v); }</del>
</pre></blockquote>
</blockquote>

</li>

<li><p>Change 33.3.2.2 [thread.thread.constr] as indicated:</p>

<blockquote>
<pre>
template &lt;class F, class... Args&gt; explicit thread(F&amp;&amp; f, Args&amp;&amp;... args);
</pre>
<blockquote>
<p>
-3- <i>Requires:</i> <tt>F</tt> and each <tt>Ti</tt> in <tt>Args</tt> shall satisfy the <tt>MoveConstructible</tt> 
requirements. <tt><i>INVOKE</i>(<del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;F&gt;(f)), 
<del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;Args&gt;(args))...)</tt> (23.14.3 [func.require]) 
shall be a valid expression.
<p/>
-4- <i>Remarks:</i> This constructor shall not participate in overload resolution if <tt>decay_t&lt;F&gt;</tt> 
is the same type as <tt>std::thread</tt>.
<p/>
-5- <i>Effects:</i> Constructs an object of type <tt>thread</tt>. The new thread of execution executes 
<tt><i>INVOKE</i>(<del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;F&gt;(f)), 
<del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;Args&gt;(args))...)</tt> with the calls
to <tt><del><i>DECAY_COPY</i></del><ins>decay_copy</ins></tt> being evaluated in the constructing thread. Any return 
value from this invocation is ignored. [<i>Note:</i> This implies that any exceptions not thrown from the invocation of 
the copy of <tt>f</tt> will be thrown in the constructing thread, not the new thread. &mdash; <i>end note</i>] If the 
invocation of <tt><i>INVOKE</i>(<del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;F&gt;(f)), 
<del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;Args&gt;(args))...)</tt> terminates
with an uncaught exception, <tt>terminate</tt> shall be called.
<p/>
[&hellip;]
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 33.6.9 [futures.async] as indicated:</p>

<blockquote>
<pre>
template &lt;class F, class... Args&gt;
  future&lt;invoke_result_t&lt;decay_t&lt;F&gt;, decay_t&lt;Args&gt;...&gt;&gt;
    async(F&amp;&amp; f, Args&amp;&amp;... args);
template &lt;class F, class... Args&gt;
  future&lt;invoke_result_t&lt;decay_t&lt;F&gt;, decay_t&lt;Args&gt;...&gt;&gt;
    async(launch policy, F&amp;&amp; f, Args&amp;&amp;... args);
</pre>
<blockquote>
<p>
-2- <i>Requires:</i> <tt>F</tt> and each <tt>Ti</tt> in <tt>Args</tt> shall satisfy the <tt>MoveConstructible</tt> requirements, and
</p>
<blockquote><pre>
<i>INVOKE</i>(<del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;F&gt;(f)),
       <del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;Args&gt;(args))...) <i>// see 23.14.3 [func.require], 33.3.2.2 [thread.thread.constr]</i>
</pre></blockquote>
<p>
-3- <i>Effects:</i> [&hellip;] The further behavior of the second function depends on the <tt>policy</tt> argument as follows 
(if more than one of these conditions applies, the implementation may choose any of the corresponding policies):
</p>
<ol style="list-style-type: none">
<li><p>(3.1) &mdash; If <tt>launch::async</tt> is set in <tt>policy</tt>, calls 
<tt><i>INVOKE</i>(<del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;F&gt;(f)), 
<del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;Args&gt;(args))...)</tt> 
(23.14.3 [func.require], 33.3.2.2 [thread.thread.constr]) as if in a new thread of execution
represented by a <tt>thread</tt> object with the calls to <tt><del><i>DECAY_COPY</i></del><ins>decay_copy</ins>()</tt> 
being evaluated in the thread that called <tt>async</tt>. Any return value is stored as the result in the shared state. 
Any exception propagated from the execution of 
<tt><i>INVOKE</i>(<del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;F&gt;(f)), 
<del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;Args&gt;(args))...)</tt> is stored as the 
exceptional result in the shared state. The <tt>thread</tt> object is stored in the shared state and affects 
the behavior of any asynchronous return objects that reference that state.
</p></li>

<li><p>(3.2) &mdash; If <tt>launch::deferred</tt> is set in <tt>policy</tt>, stores 
<tt><del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;F&gt;(f))</tt> and 
<tt><del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;Args&gt;(args))...</tt> 
in the shared state. These copies of <tt>f</tt> and <tt>args</tt> constitute
a deferred function. Invocation of the deferred function evaluates <tt><i>INVOKE</i>(std::move(g),
std::move(xyz))</tt> where <tt>g</tt> is the stored value of 
<tt><del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;F&gt;(f))</tt> and <tt>xyz</tt> is 
the stored copy of <tt><del><i>DECAY_COPY</i></del><ins>decay_copy</ins>(std::forward&lt;Args&gt;(args))...</tt>. [&hellip;]
</p></li>

<li><p>
(3.3) &mdash; [&hellip;]
</p></li>
</ol>
</blockquote>
</blockquote>
</li>

</ol>

<h2><a name="FeatureMacros"></a>Feature-testing Macros</h2>
<p>
For the purposes of SG10, this paper recommends the macro name <tt>__cpp_lib_additional_convertible_traits</tt>.
</p>

<h2><a name="Bibliography"></a>Bibliography</h2>
<p>
<a name="bib-n3255"></a><a href="http://wg21.link/n3255">N3255 Lawrence Crowl, Daniel Kr&uuml;gler: "C++ Decay Copy"</a>
<p/>
<a name="bib-P0705R0"></a><a href="http://wg21.link/p0705r0">P0705R0 Tony Van Eerd: "Implicit and Explicit Conversions"</a>
</p>

<h2><a name="Appendix"></a>Partial Sample Implementation</h2>
<p>
Example implementation for the <tt>is_nothrow_convertible</tt> type trait and the constrained <tt>decay_copy</tt> 
function template.
</p>
<blockquote>
<pre>
#include &lt;type_traits&gt; // std::enable_if, ...
#include &lt;utility&gt;     // std::forward, std::declval

namespace xstd {

namespace details {

template &lt;class From, class To, bool =
  std::disjunction&lt;
    std::is_void&lt;From&gt;, std::is_function&lt;To&gt;, std::is_array&lt;To&gt;
  &gt;::value
&gt;
struct do_is_nothrow_convertible
{
  using type = std::is_void&lt;To&gt;;
};

struct do_is_nothrow_convertible_impl
{
  template &lt;class To&gt;
  static void test_aux(To) noexcept;

  template &lt;class From, class To&gt;
  static std::bool_constant&lt;noexcept(test_aux&lt;To&gt;(std::declval&lt;From&gt;()))&gt;
  test(int);

  template &lt;class, class&gt;
  static std::false_type
  test(...);
};

template &lt;class From, class To&gt;
struct do_is_nothrow_convertible&lt;From, To, false&gt;
{
  using type = decltype(do_is_nothrow_convertible_impl::test&lt;From, To&gt;(0));
};

} // details

template &lt;class From, class To&gt;
struct is_nothrow_convertible :
  details::do_is_nothrow_convertible&lt;From, To&gt;::type
{ };

template &lt;class From, class To&gt;
inline constexpr bool is_nothrow_convertible_v 
  = is_nothrow_convertible&lt;From, To&gt;::value;

template &lt;class T&gt;
constexpr
std::enable_if_t&lt;
  std::is_convertible_v&lt;T, std::decay_t&lt;T&gt;&gt;,
  std::decay_t&lt;T&gt;
&gt;
decay_copy(T&amp;&amp; v) noexcept(is_nothrow_convertible_v&lt;T, std::decay_t&lt;T&gt;&gt;)
{
  return std::forward&lt;T&gt;(v);
}

} // xstd
</pre>
</blockquote>

</body></html>