��<html> <head> <title>Valueless Variants Considered Harmful</title> <style type="text/css"> ins { background-color: #A0FFA0; } del { background-color: #FFA0A0; } .replace { background-color: #F0F0F0; } blockquote { border: 1px #CCC solid; padding: 1em; } </style> </head> <body> <table border="0"> <tr><td>Document Number:</td><td>P0308R0</td></tr> <tr><td>Date:</td><td>2016-03-16</td></tr> <tr><td>Reply-to:</td><td>Peter Dimov &lt;<a href="mailto:pdimov@pdimov.com">pdimov@pdimov.com</a>&gt;</td></tr> <tr><td>Audience:</td><td>Library Evolution, Library</td></tr> </table> <h1>Valueless Variants Considered Harmful</h1> <h2>I. Summary</h2> <p> This paper argues in section III that when <code>variant</code>'s contained types have <code>noexcept</code> move constructors, <code>variant</code> <em>shall</em> never be valueless, that is, the specification should statically guarantee that <code>valueless_by_exception()</code> will never return <code>true</code>.</p> <p> It then proposes, in section IV, a way to extend these guarantees to types such as <code>std::list</code> that are not guaranteed to have a <code>noexcept</code> move constructor, by introducing the concept of <em>pilfering constructor</em>.</p> <p> Finally, in section V, it ventures a suggestion that at this point, we might as well get rid of <code>valueless_by_exception</code> altogether.</p> <h2>II. Introduction</h2> <p> The <code>variant</code> consensus at present, reflected in D0088R2.17, its most recent specification at time of writing, can be summarized by the following quotes by Tony Van Eerd:</p> <blockquote>The current variant basically does everything:<br /> <ul> <li>"never" empty</li> <li>no extra memory</li> <li>etc</li> </ul> OK, what doesn't it do.<br /><br /> It doesn't offer the strong exception guarantee if the move constructor throws.<br /><br /> That's it.<br /><br /> Now ask yourself:<br /> <ul> <li>how many move constructors are not noexcept</li> <li>for move constructors that are not noexcept, how many ever actually throw?</li> </ul> That second part is important. Basically it never happens, or if it does, you have bigger problems because you are so out of memory that you can't allocate 32 bytes for a node or something. (ie list constructor in some implementations). We are trying to solve a problem that doesn't really need a <b>solution</b>, but does need an <b>answer</b>, and one better than UB.<br /><br /> So, yeah, double buffering would be a solution, but you are paying a cost for something that never actually happens.<br /> Or you add an empty state, and pay the programmer cost (of dealing with empty) for something that never happens.<br /> Or you have two variants, and pay the cost of confusion, for something that never happens.<br /><br /> We, as a committee, want perfection and want to be concerned about the corner cases, but in reality, they never happen.</blockquote> <p>and David Sankel:</p> <blockquote>If a developer conforms to the sane subset of C++ where move constructors don't throw, then their variants won't get into the valueless state.</blockquote> <p> In other words, the current consensus acknowledges that <code>variant</code> getting in the valueless state is undesirable, and I absolutely agree.</p> <p> I however have two objections to the above quotes. First, the statements</p> <ul> <li>"<code>variant</code> doesn't offer the strong exception guarantee if the move constructor throws."</li> <li>"If a developer conforms to the sane subset of C++ where move constructors don't throw, then their variants won't get into the valueless state."</li> </ul> <p> are simply false under the current specification. <code>variant</code> habitually does not give the strong exception guarantee on assignment, and can go into the valueless state, even when the move constructors of the contained types don't throw.</p> <p> Second, I do not consider the "will never happen" philosophy good enough for a standard C++ component. It's fine for a TS, which is meant to be experimental, gather experience, and can be fixed when a defect is discovered without regard to code being broken. Once a component gets into the C++ standard, changing it becomes very hard.</p> <p> "Will never happen" can be, pragmatically speaking, the right strategy under many circumstances, when the cost of the solution outweighs the cost of the problem. It does have its disadvantages though, one of which is that "never happen" scenarios, being extremely rare, are never tested and therefore tend to occur in production when their costs are high. (Insert Ariane 5 reference here.)</p> <p> That is why some programmers prefer to rely on static (compile-time) guarantees that the scenarios that "never happen" do indeed never happen, and <b>it is my opinion that it is a requirement for a C++17 <code>variant</code> to provide such a static, compile-time, guarantee that it will never go into a valueless state if certain restrictions, which can be checked at compile time, are met.</b></p> <p> Axel Naumann prefers a different approach:</p> <blockquote>I want the wording to allow your suggestions without requiring them.</blockquote> <p> but I respectfully disagree. "Allowed but not required" is not good enough. First, "allowed but not required" does not give compile-time guarantees. Second, it hampers portability. Third, the wording is subtle and this makes it possible for what is intended to allow but not require to turn out to disallow.</p> <h2> III. Never Valueless</h2> <p> The previous section concluded that <code>variant</code> should provide a static, compile-time, guarantee that it will never go into a valueless state if certain restrictions, which can be checked at compile time, are met. What should those restrictions be?</p> <p> Unsurprisingly, and in agreement with the existing prevailing opinion, that the move constructors of the contained types are <code>noexcept</code>.</p> <p> (Note that move <em>assignments</em> being <code>noexcept</code> is not required. One might naively think that a type that has a <code>noexcept</code> move constructor would also have a <code>noexcept</code> move assignment so we might as well require that with no loss of generality, but as usual, the standard library has a surprise for us, in that <code>std::vector</code>'s move assignment is not necessarily <code>noexcept</code>.)</p> <p> What do we need to change in D0088R2.17 to fulfill this requirement?</p> <p> There are only two ways for a <code>variant</code> to become valueless: assignment and <code>emplace</code>. Let's consider all their variations in turn.</p> <h3><code>variant&amp; operator=(const variant&amp; rhs);</code></h3> <blockquote> <p><em>Effects:</em> <ins>Let <code>j</code> be <code>rhs.index()</code>.</ins></p> <ul> <li>If neither <code>*this</code> nor <code>rhs</code> holds a value, there is no effect. Otherwise</li> <li>if <code>*this</code> holds a value but <code>rhs</code> does not, destroys the value contained in <code>*this</code> and sets <code>*this</code> to not hold a value. Otherwise,</li> <li>if <code>index() == <del>rhs.index()</del><ins>j &amp;&amp; is_nothrow_copy_assignable_v&lt;T_j&gt;</ins></code>, assigns the value contained in <code>rhs</code> to the value contained in <code>*this</code>. Otherwise,</li> <li><ins>if <code>index() == j &amp;&amp; is_nothrow_move_assignable_v&lt;T_j&gt;</code>, copies the value contained in <code>rhs</code> to a temporary <code>TMP</code>, then assigns <code>std::forward&lt;T_j&gt;(TMP)</code> to the value contained in <code>*this</code>. Otherwise,</ins></li> <li><ins>if <code>index() == j &amp;&amp; !is_nothrow_move_constructible_v&lt;T_j&gt;</code>, assigns the value contained in <code>rhs</code> to the value contained in <code>*this</code>. Otherwise,</ins></li> <li>copies the value contained in <code>rhs</code> to a temporary<ins> <code>TMP</code></ins>, then destroys any value contained in <code>*this</code>. Sets <code>*this</code> to hold the same alternative index as <code>rhs</code> and initializes the value contained in <code>*this</code> as if direct-non-list-initializing an object of type <code>T_j</code> with <code>std::forward&lt;T_j&gt;(TMP)</code><del>, with <code>TMP</code> being the temporary and <code>j</code> being <code>rhs.index()</code></del>.</li> </ul> <p><em>Returns:</em> <code>*this</code>.</p> <p><em>Postconditions:</em> <code>index() == rhs.index()</code></p> <p><em>Remarks:</em> This function shall not participate in overload resolution unless <code>is_copy_constructible_v&lt;T_i&gt; &amp;&amp; is_move_constructible_v&lt;T_i&gt; &amp;&amp; is_copy_assignable_v&lt;T_i&gt;</code> is <code>true</code> for all <code>i</code>.</p> <ul> <li>If an exception is thrown during the call to <code>T_j</code>'s copy assignment, the state of the contained value is as defined by the exception safety guarantee of <code>T_j</code>'s copy assignment; <code>index()</code> will be <code>j</code>.</li> <li>If an exception is thrown during the call to <code>T_j</code>'s copy constructor (with <code>j</code> being <code>rhs.index()</code>), <code>*this</code> will remain unchanged.</li> <li>If an exception is thrown during the call to <code>T_j</code>'s move constructor, the <code>variant</code> will hold no value.</li> </ul> </blockquote> <p> These changes make sure that when the move constructor of <code>T_j</code> is <code>noexcept</code>, the assignment will never put the <code>variant</code> into the valueless state and that it will provide the strong exception safety guarantee.</p> <h3><code>variant&amp; operator=(variant&amp;&amp; rhs) noexcept(<em>see below</em>);</code></h3> <blockquote> <p><em>Effects:</em> <ins>Let <code>j</code> be <code>rhs.index()</code>.</ins></p> <ul> <li>If neither <code>*this</code> nor <code>rhs</code> holds a value, there is no effect. Otherwise</li> <li>if <code>*this</code> holds a value but <code>rhs</code> does not, destroys the value contained in <code>*this</code> and sets <code>*this</code> to not hold a value. Otherwise,</li> <li>if <code>index() == <del>rhs.index()</del><ins>j &amp;&amp; (is_nothrow_move_assignable_v&lt;T_j&gt; || !is_nothrow_move_constructible_v&lt;T_j&gt;)</ins></code>, assigns <code>std::forward&lt;T_j&gt;(get&lt;j&gt;(rhs))</code> to the value contained in <code>*this</code><del>, with <code>j</code> being <code>index()</code></del>. Otherwise,</li> <li>destroys any value contained in <code>*this</code>. Sets <code>*this</code> to hold the same alternative index as <code>rhs</code> and initializes the value contained in <code>*this</code> as if direct-non-list-initializing an object of type <code>T_j</code> with <code>std::forward&lt;T_j&gt;(get&lt;j&gt;(rhs))</code><del> with <code>j</code> being <code>rhs.index()</code></del>.</li> </ul> <p><em>Returns:</em> <code>*this</code>.</p> <p><em>Remarks:</em> This function shall not participate in overload resolution unless <code>is_move_constructible_v&lt;T_i&gt; &amp;&amp; is_move_assignable_v&lt;T_i&gt;</code> is <code>true</code> for all <code>i</code>. The expression inside <code>noexcept</code> is equivalent to: <code>is_nothrow_move_constructible_v&lt;T_i&gt;<del> &amp;&amp; is_nothrow_move_assignable_v&lt;T_i&gt;</del></code> for all <code>i</code>.</p> <ul> <li>If an exception is thrown during the call to <code>T_j</code>'s move constructor<del> (with <code>j</code> being <code>rhs.index()</code>)</del>, the <code>variant</code> will hold no value.</li> <li>If an exception is thrown during the call to <code>T_j</code>'s move assignment, the state of the contained value is as defined by the exception safety guarantee of <code>T_j</code>'s move assignment; <code>index()</code> will be <code>j</code>.</li> </ul> </blockquote> <p> As above: These changes make sure that when the move constructor of <code>T_j</code> is <code>noexcept</code>, the assignment will never put the <code>variant</code> into the valueless state and that it will provide the strong exception safety guarantee with respect to <code>*this</code>.</p> <h3><code>template &lt;class T&gt; variant&amp; operator=(T&amp;&amp; t) noexcept(<em>see below</em>);</code></h3> <blockquote> <p><em>Effects:</em> <ins><code>operator=(variant(std::forward&lt;T&gt;(t)))</code>.</ins></p> <p><em>Returns:</em> <code>*this</code>.</p> <p><em>Remarks:</em> This function shall not participate in overload resolution unless <code>is_same_v&lt;decay_t&lt;T&gt;, variant&gt;</code> is <code>false</code> <ins> and unless <code>variant(std::forward&lt;T&gt;(t))</code> is a valid expression. The expression inside <code>noexcept</code> is <code>noexcept(operator=(variant(std::forward&lt;T&gt;(t))))</code></ins>.</p> </blockquote> <p> The existing specification of this assignment needlessly duplicates the wording in <code>variant::variant(T&amp;&amp; t)</code>that selects the alternative using overload resolution, and does not provide any non-valueless guarantees due to initializing directly from <code>t</code> instead of using the potentially <code>noexcept</code> move constructor of the selected contained type. I have opted to use the cleanest fix in the above suggested wording. It's possible to expand the expression <code>operator=(variant(std::forward&lt;T&gt;(t)))</code> into the specification, but the only thing that this gains is collapsing two adjacent move constructors calls into one, and the implementation is permitted to do this anyway under the as-if rule, so the benefits do not outweigh the costs of using the more complicated wording, with the associated possibility of getting it wrong.</p> <p> Or, another option is to remove this assignment operator altogether, which would be equivalent to this specification.</p> <h3><code>template &lt;size_t I, class... Args&gt; void emplace(Args&amp;&amp;... args);</code></h3> <blockquote> <p><em>Requires:</em> <code>I &lt; sizeof...(Types)</code></p> <p><em>Effects:</em> <del>Destroys the currently contained value if <code>valueless_by_exception()</code> is <code>false</code>. Then direct-initializes the contained value as if constructing a value of type <code>T_I</code> with the arguments <code>std::forward&lt;Args&gt;(args)...</code>.</del></p> <ul> <li><ins>If <code>is_nothrow_constructible_v&lt;T_I, Args&amp;&amp;...&gt; || !is_nothrow_move_constructible_v&lt;T_I&gt;</code>, destroys the currently contained value if <code>valueless_by_exception()</code> is <code>false</code> and direct-initializes the contained value as if constructing a value of type <code>T_I</code> with the arguments <code>std::forward&lt;Args&gt;(args)...</code>. Otherwise,</ins></li> <li><ins>direct-initializes a temporary <code>TMP</code> of type <code>T_I</code> with the arguments <code>std::forward&lt;Args&gt;(args)...</code>, destroys the currently contained value if <code>valueless_by_exception()</code> is <code>false</code> and direct-initializes the contained value as if constructing a value of type <code>T_I</code> with the argument <code>std::forward&lt;T_I&gt;(TMP)</code>.</ins></li> </ul> <p><em>Postcondition:</em> <code>index()</code> is <code>I</code>.</p> <p><em>Throws:</em> Any exception thrown during the initialization of the contained value.</p> <p><em>Remarks:</em> This function shall not participate in overload resolution unless <code>is_constructible_v&lt;T_I, Args&amp;&amp;...&gt;</code> is <code>true</code>. If an exception is thrown during the initialization of the contained value, the <code>variant</code> will not hold a value.</p> </blockquote> <p> As above: These changes make sure that when the move constructor of <code>T_I</code> is <code>noexcept</code>, <code>emplace</code> will never put the <code>variant</code> into the valueless state and that it will provide the strong exception safety guarantee.</p> <h3><code>template &lt;size_t I, class U, class... Args&gt; void emplace(initializer_list&ltU&gt; il, Args&amp;&amp;... args);</code></h3> <blockquote> <p><em>Requires:</em> <code>I &lt; sizeof...(Types)</code></p> <p><em>Effects:</em> <del>Destroys the currently contained value if <code>valueless_by_exception()</code> is <code>false</code>. Then direct-initializes the contained value as if constructing a value of type <code>T_I</code> with the arguments <code>il, std::forward&lt;Args&gt;(args)...</code>.</del></p> <ul> <li><ins>If <code>is_nothrow_constructible_v&lt;T_I, initializer_list&lt;U&gt;&amp;, Args&amp;&amp;...&gt; || !is_nothrow_move_constructible_v&lt;T_I&gt;</code>, destroys the currently contained value if <code>valueless_by_exception()</code> is <code>false</code> and direct-initializes the contained value as if constructing a value of type <code>T_I</code> with the arguments <code>il, std::forward&lt;Args&gt;(args)...</code>. Otherwise,</ins></li> <li><ins>direct-initializes a temporary <code>TMP</code> of type <code>T_I</code> with the arguments <code>il, std::forward&lt;Args&gt;(args)...</code>, destroys the currently contained value if <code>valueless_by_exception()</code> is <code>false</code> and direct-initializes the contained value as if constructing a value of type <code>T_I</code> with the argument <code>std::forward&lt;T_I&gt;(TMP)</code>.</ins></li> </ul> <p><em>Postcondition:</em> <code>index()</code> is <code>I</code>.</p> <p><em>Throws:</em> Any exception thrown during the initialization of the contained value.</p> <p><em>Remarks:</em> This function shall not participate in overload resolution unless <code>is_constructible_v&lt;T_I, initializer_list&lt;U&gt;&amp;, Args&amp;&amp;...&gt;</code> is <code>true</code>. If an exception is thrown during the initialization of the contained value, the <code>variant</code> will not hold a value.</p> </blockquote> <p> As above.</p> <h3><code>template &lt;class T, class... Args&gt; void emplace(Args&amp;&amp;... args);</code></h3> <h3><code>template &lt;class T, class U, class... Args&gt; void emplace(initializer_list&ltU&gt; il, Args&amp;&amp;... args);</code></h3> <p> These two overloads of <code>emplace</code> are specified in terms of the index-based ones, so no changes are required.</p> <h3><code>constexpr bool valueless_by_exception() const noexcept;</code></h3> <blockquote> <p><em>Effects:</em> Returns <code>false</code> if and only if the variant holds a value. [Note: A variant will not hold a value if an exception is thrown <ins>from the move constructor of the contained type</ins> during a type-changing assignment or emplacement. &mdash; <em>end note</em>]</p> <p><em>Remarks:</em> <ins> This function shall be <code>static</code> and always return <code>false</code> when <code>is_nothrow_move_constructible_v&lt;T_i&gt;</code> is <code>true</code> for all <code>i</code>. [Note: <code>static_assert(variant&lt;Types...&gt;::valueless_by_exception() == false);</code> may be used to verify that a <code>variant&lt;Types...&gt;</code> may never become valueless. &mdash; <em>end note</em>]</ins></p> </blockquote> <h2>IV. Pilfering</h2> <p> The changes in the preceding section do give us the necessary guarantees in most cases, but there's still a problem with, for example, <code>variant&lt;int, std::list&lt;int&gt;&gt;</code>. Under some implementations, every <code>list</code> instance allocates a sentinel node, and since <code>list</code>'s move constructor needs to leave the moved-from object in a valid state, it can't steal its sentinel node for the new instance, forcing an allocation and therefore precluding <code>noexcept</code>. This means that <code>variant&lt;int, std::list&lt;int&gt;&gt;</code> would be guaranteed valueless on some implementations and not on others, which is a portability concern.</p> <p> It so happens that the implementation of <code>variant</code> usually moves from an internal temporary that is later destroyed and is invisible to the outside code. A move-constructed <code>list</code> could, therefore, steal the sentinel node of this temporary, but there is no standard protocol for doing so.</p> <p> The implementation of <code>std::variant</code> could, of course, detect <code>std::list</code> and use some internal constructor instead, and one might argue that a quality implementation ought to do so, but this cannot extend to user-defined types, or even to <code>std::pair&lt;T, std::list&lt;int&gt;&gt;</code>.</p> <p> This section proposes a general mechanism to enable such semi-destructive move construction, after which the moved-from object can be safely destroyed, but is not guaranteed to be usable in any other way. This semi-destructive move is called <em>pilfering</em> and is accessed by a constructor with the signature <code>T::T(std::pilfered&lt;T&gt;) noexcept</code>, where <code>std::pilfered&lt;T&gt;</code> wraps a reference to <code>T</code>:</p> <blockquote> <pre>template&lt;class T&gt; class pilfered { private: T&amp; t_; public: explicit constexpr pilfered(T&amp;&amp; t) noexcept: t_(t) {} constexpr T&amp; get() const noexcept { return t_; } constexpr T* operator-&gt;() const noexcept { return std::addressof(t_); } };</pre> </blockquote> <p>and there's also a corresponding type trait <code>std::is_pilfer_constructible&lt;T&gt;</code> and a helper function <code>std::pilfer(t)</code> which is analogous to <code>std::move(t)</code>:</p> <blockquote> <pre>template&lt;class T&gt; struct is_pilfer_constructible: std::integral_constant&lt;bool, std::is_nothrow_move_constructible&lt;T&gt;::value || (std::is_nothrow_constructible&lt;T, pilfered&lt;T&gt;&gt;::value && !std::is_nothrow_constructible&lt;T, __not_pilfered&lt;T&gt;&gt;::value)&gt; { }; template&lt;class T&gt; constexpr decltype(auto) pilfer(T&amp;&amp; t) noexcept { using U = std::remove_reference_t&lt;T&gt;; return std::conditional_t&lt;std::is_nothrow_move_constructible&lt;U&gt;::value || !is_pilfer_constructible&lt;U&gt;::value, U&amp;&amp;, pilfered&lt;U&gt;&gt;(std::move(t)); } </pre> </blockquote> <p> <code>is_pilfer_constructible&lt;T&gt;</code> reports true when <code>T</code> has either a <code>noexcept</code> move constructor or a <code>noexcept</code> pilfering constructor. It checks for construction from <code>__not_pilfered</code>, which has the same definition as <code>pilfered</code>, in order to detect false positives caused by types that are constructible from an argument of any type.</p> <p> <code>pilfer(t)</code> returns either an rvalue reference to <code>t</code> or a <code>pilfered&lt;T&gt;</code> instance that refers to <code>t</code>, as appropriate.</p> <p> In the past I have suggested a pilfering mechanism that uses a function instead of a constructor, but a function-based approach does not compose. A pilfering constructor for</p> <blockquote><pre>struct X { T t; U u; };</pre></blockquote> <p> where <code>T</code> and <code>U</code> are known to be either <code>noexcept</code> move constructible or pilfer constructible, can be added via</p> <blockquote><pre>struct X { T t; U u; X(std::pilfered&lt;X&gt; r) noexcept: t(std::pilfer(r-&gt;t)), u(std::pilfer(r-&gt;u)) {} };</pre></blockquote> <p> which is analogous to adding an ordinary move constructor.</p> <p> The case in which <code>T</code> and <code>U</code> are not known in advance, such as with <code>std::pair</code>, becomes more convoluted because the initialization of the members might throw, and we don't want to define the pilfering constructor in this case (it makes no sense to define a pilfering constructor that is not <code>noexcept</code>.) <code>is_pilfer_constructible&lt;T&gt;</code> can be used to disable the pilfering constructor via SFINAE. One possible implementation of <code>X</code>'s pilfering constructor for the template case would be</p> <blockquote><pre>template&lt;class T, class U&gt; struct X { T t; U u; template&lt;class T2 = T, class U2 = U, class E = int[std::is_pilfer_constructible_v&lt;T2&gt; &amp;&amp; std::is_pilfer_constructible_v&lt;U2&gt;? 1: -1]&gt; X(std::pilfered&lt;X&gt; r) noexcept: t(std::pilfer(r-&gt;t)), u(std::pilfer(r-&gt;u)) {} };</pre></blockquote> <p> <code>is_pilfer_constructible</code> is satisfied by either a <code>noexcept</code> move constructor or a <code>noexcept</code> pilfering constructor, and the expression <code>t(std::pilfer(r-&gt;t))</code> will work with either, so a combinatorial explosion does not occur.</p> <p> The standard wording for pilfering (relative to N4567) is given below.</p> <p> &mdash; Add to the synopsis of header <code>&lt;utility&gt;</code> in [utility] the following:</p> <blockquote> <pre><ins>// 20.x, Pilfering template&lt;class T&gt; class pilfered; template&lt;class T&gt; constexpr decltype(auto) pilfer(T&amp;&amp; t) noexcept;</ins></pre> </blockquote> <p> &mdash; After [intseq], add new sections [pilfered] and [pilfer]:</p> <blockquote> <p><ins><strong>20.x Class template <code>pilfered</code> [pilfered]</strong></ins></p> <pre><ins>template&lt;class T&gt; class pilfered { private: T&amp; t_; public: explicit constexpr pilfered(T&amp;&amp; t) noexcept; constexpr T&amp; get() const noexcept; constexpr T* operator-&gt;() const noexcept; };</ins></pre> <p> <ins><code>pilfered&lt;T&gt;</code> wraps a reference to <code>T</code> and is used as an argument to <code>T</code>'s <em>pilfering constructor</em>. Pilfering constructors have the form <code>T::T(pilfered&lt;T&gt;) noexcept</code> and perform a semi-destructive move. After a call to a pilfering constructor, the moved-from object can be safely destroyed, but cannot be used in any other way.</ins></p> <p><ins><code>explicit constexpr pilfered(T&amp;&amp; t) noexcept;</code></ins></p> <p style="margin-left: 2.5em;"><ins><em>Effects:</em> Initializes <code>t_</code> to <code>t</code>.</ins></p> <p><ins><code>constexpr T&amp; get() const noexcept;</code></ins></p> <p style="margin-left: 2.5em;"><ins><em>Returns:</em> <code>t_</code>.</ins></p> <p><ins><code>constexpr T* operator-&gt;() const noexcept;</code></ins></p> <p style="margin-left: 2.5em;"><ins><em>Returns:</em> <code>addressof(t_)</code>.</ins></p> <p><ins><strong>20.x Function template <code>pilfer</code> [pilfer]</strong></ins></p> <pre><ins>template&lt;class T&gt; constexpr decltype(auto) pilfer(T&amp;&amp; t) noexcept;</ins></pre> <p style="margin-left: 2.5em;"><ins><em>Returns:</em> <code>conditional_t&lt;is_nothrow_move_constructible_v&lt;U&gt; || !is_pilfer_constructible_v&lt;U&gt;, U&amp;&amp;, pilfered&lt;U&gt;&gt;(move(t))</code>, where <code>U</code> is <code>remove_reference_t&lt;T&gt;</code>.</ins></p> </blockquote> <p> &mdash; In the synopsis of header <code>&lt;type_traits&gt;</code> [meta.type.synop], in the group of type properties, add the following:</p> <blockquote> <pre>template &lt;class T&gt; struct is_nothrow_move_constructible; <ins>template &lt;class T&gt; struct is_pilfer_constructible;</ins></pre> </blockquote> <blockquote> <pre>template &lt;class T&gt; constexpr bool is_nothrow_move_constructible_v = is_nothrow_move_constructible&lt;T&gt;::value; <ins>template &lt;class T&gt; constexpr bool is_pilfer_constructible_v = is_pilfer_constructible&lt;T&gt;::value;</ins></pre> </blockquote> <p> &mdash; In section [meta.unary.prop], add the following paragraph before Table 49:</p> <blockquote> <p> <ins>In the following table, <code>__not_pilfered</code> is a class template with an unspecified name whose definition is the same as that of <code>pilfered</code>.</ins></p> </blockquote> <p> &mdash; In section [meta.unary.prop], add to Table 49 the following row:</p> <table border="1" cellspacing="0" cellpadding="6" style="width: 64em; margin-left: 2.5em;"><tr> <td><ins><code>template &lt;class T&gt; struct is_pilfer_constructible;</code></ins></td> <td><ins>For a referenceable type <code>T</code>, the same result as <code>is_nothrow_move_constructible_v&ltT&gt; || (is_nothrow_constructible_v&lt;T, pilfered&lt;T&gt;&gt; &amp;&amp; !is_nothrow_constructible_v&lt;T, __not_pilfered&lt;T&gt;&gt;</code>), otherwise false.<br /><br /> [Note: <code>__not_pilfered</code> is used to avoid false positives caused by types that can be constructed from any argument. &mdash; <em>end note</em>]</ins></td> <td><ins><code>T</code> shall be a complete type, (possibly cv-qualified) <code>void</code>, or an array of unknown bound.</ins></td> </tr></table> <p> &mdash; Add to <code>struct pair</code> in [pairs.pair] the following constructor:</p> <blockquote> <pre>pair(const pair&amp;) = default; pair(pair&amp;&amp;) = default; <ins>pair(pilfered&lt;pair&gt; r) noexcept;</ins> constexpr pair(); </pre> </blockquote> <p> &mdash; Add to [pairs.pair] the following section:</p> <blockquote> <pre><ins>pair(pilfered&lt;pair&gt; r) noexcept;</ins></pre> <p><ins><em>Effects:</em> Initializes <code>first</code> with <code>pilfer(r->first)</code> and <code>second</code> with <code>pilfer(r->second)</code>.</ins></p> <p><ins><em>Remarks:</em> This constructor shall not participate in overload resolution unless <code>is_pilfer_constructible&lt;T1&gt;::value &amp;&amp; is_pilfer_constructible&lt;T2&gt;::value</code>.</ins></p> </blockquote> <p> &mdash; Add to <code>class tuple</code> in [tuple.tuple] the following constructor:</p> <blockquote> <pre>tuple(const tuple&amp;) = default; tuple(tuple&amp;&amp;) = default; <ins>tuple(pilfered&lt;tuple&gt; u) noexcept;</ins> </pre> </blockquote> <p> &mdash; Add to [tuple.cnstr] the following section:</p> <blockquote> <pre><ins>tuple(pilfered&lt;tuple&gt; u) noexcept;</ins></pre> <p><ins><em>Effects:</em> For all <em>i</em>, initializes the <em>i<sup>th</sup></em> element of <code>*this</code> with <code>get&lt;<em>i</em>&gt;(u.get())</code> when <code><em>T<sub>i</sub></em></code> is a reference type, <code>pilfer(get&lt;<em>i</em>&gt;(u.get()))</code> otherwise.</ins></p> <p><ins><em>Remarks:</em> This constructor shall not participate in overload resolution unless <code>is_pilfer_constructible&lt;<em>T<sub>i</sub></em>&gt;::value</code> is <code>true</code> for all <em>i</em>.</ins></p> </blockquote> <p> &mdash; Add to <code>class deque</code> in [deque.overview] the following constructor:</p> <blockquote> <pre>deque(const deque&amp; x); deque(deque&amp;&amp;); <ins>deque(pilfered&lt;deque&gt; x) noexcept;</ins> </pre> </blockquote> <p> &mdash; Add to [deque.cons] the following section:</p> <blockquote> <pre><ins>deque(pilfered&lt;deque&gt; x) noexcept;</ins></pre> <p><ins><em>Effects:</em> Constructs <code>*this</code> from the contents of the object referenced by <code>x.get()</code>.</ins></p> <p><ins><em>Postconditions:</em> <code>*this</code> has the value the object referenced by <code>x.get()</code> had before the call.</ins></p> <p><ins><em>Remarks:</em> After this constructor, the object referenced by <code>x.get()</code> can safely be destroyed. The behavior of any other access to the object referenced by <code>x.get()</code> is undefined.</ins></p> </blockquote> <p> &mdash; Add to <code>class forward_list</code> in [forwardlist.overview] the following constructor:</p> <blockquote> <pre>forward_list(const forward_list&amp; x); forward_list(forward_list&amp;&amp; x); <ins>forward_list(pilfered&lt;forward_list&gt; x) noexcept;</ins> </pre> </blockquote> <p> &mdash; Add to [forwardlist.cons] the following section:</p> <blockquote> <pre><ins>forward_list(pilfered&lt;forward_list&gt; x) noexcept;</ins></pre> <p><ins><em>Effects:</em> Constructs <code>*this</code> from the contents of the object referenced by <code>x.get()</code>.</ins></p> <p><ins><em>Postconditions:</em> <code>*this</code> has the value the object referenced by <code>x.get()</code> had before the call.</ins></p> <p><ins><em>Remarks:</em> After this constructor, the object referenced by <code>x.get()</code> can safely be destroyed. The behavior of any other access to the object referenced by <code>x.get()</code> is undefined.</ins></p> </blockquote> <p> &mdash; Add to <code>class list</code> in [list.overview] the following constructor:</p> <blockquote> <pre>list(const list&amp; x); list(list&amp;&amp; x); <ins>list(pilfered&lt;list&gt; x) noexcept;</ins> </pre> </blockquote> <p> &mdash; Add to [list.cons] the following section:</p> <blockquote> <pre><ins>list(pilfered&lt;list&gt; x) noexcept;</ins></pre> <p><ins><em>Effects:</em> Constructs <code>*this</code> from the contents of the object referenced by <code>x.get()</code>.</ins></p> <p><ins><em>Postconditions:</em> <code>*this</code> has the value the object referenced by <code>x.get()</code> had before the call.</ins></p> <p><ins><em>Remarks:</em> After this constructor, the object referenced by <code>x.get()</code> can safely be destroyed. The behavior of any other access to the object referenced by <code>x.get()</code> is undefined.</ins></p> </blockquote> <p> &mdash; Add to <code>class map</code> in [map.overview] the following constructor:</p> <blockquote> <pre>map(const map&amp; x); map(map&amp;&amp; x); <ins>map(pilfered&lt;map&gt; x) noexcept;</ins> </pre> </blockquote> <p> &mdash; Add to [map.cons] the following section:</p> <blockquote> <pre><ins>map(pilfered&lt;map&gt; x) noexcept;</ins></pre> <p><ins><em>Effects:</em> Constructs <code>*this</code> from the contents of the object referenced by <code>x.get()</code>.</ins></p> <p><ins><em>Postconditions:</em> <code>*this</code> has the value the object referenced by <code>x.get()</code> had before the call.</ins></p> <p><ins><em>Remarks:</em> After this constructor, the object referenced by <code>x.get()</code> can safely be destroyed. The behavior of any other access to the object referenced by <code>x.get()</code> is undefined.</ins></p> </blockquote> <p> &mdash; Add to <code>class multimap</code> in [multimap.overview] the following constructor:</p> <blockquote> <pre>multimap(const multimap&amp; x); multimap(multimap&amp;&amp; x); <ins>multimap(pilfered&lt;multimap&gt; x) noexcept;</ins> </pre> </blockquote> <p> &mdash; Add to [multimap.cons] the following section:</p> <blockquote> <pre><ins>multimap(pilfered&lt;multimap&gt; x) noexcept;</ins></pre> <p><ins><em>Effects:</em> Constructs <code>*this</code> from the contents of the object referenced by <code>x.get()</code>.</ins></p> <p><ins><em>Postconditions:</em> <code>*this</code> has the value the object referenced by <code>x.get()</code> had before the call.</ins></p> <p><ins><em>Remarks:</em> After this constructor, the object referenced by <code>x.get()</code> can safely be destroyed. The behavior of any other access to the object referenced by <code>x.get()</code> is undefined.</ins></p> </blockquote> <p> &mdash; Add to <code>class set</code> in [set.overview] the following constructor:</p> <blockquote> <pre>set(const set&amp; x); set(set&amp;&amp; x); <ins>set(pilfered&lt;set&gt; x) noexcept;</ins> </pre> </blockquote> <p> &mdash; Add to [set.cons] the following section:</p> <blockquote> <pre><ins>set(pilfered&lt;set&gt; x) noexcept;</ins></pre> <p><ins><em>Effects:</em> Constructs <code>*this</code> from the contents of the object referenced by <code>x.get()</code>.</ins></p> <p><ins><em>Postconditions:</em> <code>*this</code> has the value the object referenced by <code>x.get()</code> had before the call.</ins></p> <p><ins><em>Remarks:</em> After this constructor, the object referenced by <code>x.get()</code> can safely be destroyed. The behavior of any other access to the object referenced by <code>x.get()</code> is undefined.</ins></p> </blockquote> <p> &mdash; Add to <code>class multiset</code> in [multiset.overview] the following constructor:</p> <blockquote> <pre>multiset(const multiset&amp; x); multiset(multiset&amp;&amp; x); <ins>multiset(pilfered&lt;multiset&gt; x) noexcept;</ins> </pre> </blockquote> <p> &mdash; Add to [multiset.cons] the following section:</p> <blockquote> <pre><ins>multiset(pilfered&lt;multiset&gt; x) noexcept;</ins></pre> <p><ins><em>Effects:</em> Constructs <code>*this</code> from the contents of the object referenced by <code>x.get()</code>.</ins></p> <p><ins><em>Postconditions:</em> <code>*this</code> has the value the object referenced by <code>x.get()</code> had before the call.</ins></p> <p><ins><em>Remarks:</em> After this constructor, the object referenced by <code>x.get()</code> can safely be destroyed. The behavior of any other access to the object referenced by <code>x.get()</code> is undefined.</ins></p> </blockquote> <p> &mdash; Add to <code>class unordered_map</code> in [unord.map.overview] the following constructor:</p> <blockquote> <pre>unordered_map(const unordered_map&amp;); unordered_map(unordered_map&amp;&amp;); <ins>unordered_map(pilfered&lt;unordered_map&gt; x) noexcept;</ins> </pre> </blockquote> <p> &mdash; Add to [unord.map.cnstr] the following section:</p> <blockquote> <pre><ins>unordered_map(pilfered&lt;unordered_map&gt; x) noexcept;</ins></pre> <p><ins><em>Effects:</em> Constructs <code>*this</code> from the contents of the object referenced by <code>x.get()</code>.</ins></p> <p><ins><em>Postconditions:</em> <code>*this</code> has the value the object referenced by <code>x.get()</code> had before the call.</ins></p> <p><ins><em>Remarks:</em> After this constructor, the object referenced by <code>x.get()</code> can safely be destroyed. The behavior of any other access to the object referenced by <code>x.get()</code> is undefined.</ins></p> </blockquote> <p> &mdash; Add to <code>class unordered_multimap</code> in [unord.multimap.overview] the following constructor:</p> <blockquote> <pre>unordered_multimap(const unordered_multimap&amp;); unordered_multimap(unordered_multimap&amp;&amp;); <ins>unordered_multimap(pilfered&lt;unordered_multimap&gt; x) noexcept;</ins> </pre> </blockquote> <p> &mdash; Add to [unord.multimap.cnstr] the following section:</p> <blockquote> <pre><ins>unordered_multimap(pilfered&lt;unordered_multimap&gt; x) noexcept;</ins></pre> <p><ins><em>Effects:</em> Constructs <code>*this</code> from the contents of the object referenced by <code>x.get()</code>.</ins></p> <p><ins><em>Postconditions:</em> <code>*this</code> has the value the object referenced by <code>x.get()</code> had before the call.</ins></p> <p><ins><em>Remarks:</em> After this constructor, the object referenced by <code>x.get()</code> can safely be destroyed. The behavior of any other access to the object referenced by <code>x.get()</code> is undefined.</ins></p> </blockquote> <p> &mdash; Add to <code>class unordered_set</code> in [unord.set.overview] the following constructor:</p> <blockquote> <pre>unordered_set(const unordered_set&amp;); unordered_set(unordered_set&amp;&amp;); <ins>unordered_set(pilfered&lt;unordered_set&gt; x) noexcept;</ins> </pre> </blockquote> <p> &mdash; Add to [unord.set.cnstr] the following section:</p> <blockquote> <pre><ins>unordered_set(pilfered&lt;unordered_set&gt; x) noexcept;</ins></pre> <p><ins><em>Effects:</em> Constructs <code>*this</code> from the contents of the object referenced by <code>x.get()</code>.</ins></p> <p><ins><em>Postconditions:</em> <code>*this</code> has the value the object referenced by <code>x.get()</code> had before the call.</ins></p> <p><ins><em>Remarks:</em> After this constructor, the object referenced by <code>x.get()</code> can safely be destroyed. The behavior of any other access to the object referenced by <code>x.get()</code> is undefined.</ins></p> </blockquote> <p> &mdash; Add to <code>class unordered_multiset</code> in [unord.multiset.overview] the following constructor:</p> <blockquote> <pre>unordered_multiset(const unordered_multiset&amp;); unordered_multiset(unordered_multiset&amp;&amp;); <ins>unordered_multiset(pilfered&lt;unordered_multiset&gt; x) noexcept;</ins> </pre> </blockquote> <p> &mdash; Add to [unord.multiset.cnstr] the following section:</p> <blockquote> <pre><ins>unordered_multiset(pilfered&lt;unordered_multiset&gt; x) noexcept;</ins></pre> <p><ins><em>Effects:</em> Constructs <code>*this</code> from the contents of the object referenced by <code>x.get()</code>.</ins></p> <p><ins><em>Postconditions:</em> <code>*this</code> has the value the object referenced by <code>x.get()</code> had before the call.</ins></p> <p><ins><em>Remarks:</em> After this constructor, the object referenced by <code>x.get()</code> can safely be destroyed. The behavior of any other access to the object referenced by <code>x.get()</code> is undefined.</ins></p> </blockquote> <p> Given these changes, the <code>variant</code> specification needs to be updated to use pilfer constructors, as follows. The differences are relative to the wording in the preceding section.</p> <h3><code>variant&amp; operator=(const variant&amp; rhs);</code></h3> <blockquote> <p><em>Effects:</em> Let <code>j</code> be <code>rhs.index()</code>.</p> <ul> <li>If neither <code>*this</code> nor <code>rhs</code> holds a value, there is no effect. Otherwise</li> <li>if <code>*this</code> holds a value but <code>rhs</code> does not, destroys the value contained in <code>*this</code> and sets <code>*this</code> to not hold a value. Otherwise,</li> <li>if <code>index() == j &amp;&amp; is_nothrow_copy_assignable_v&lt;T_j&gt;</code>, assigns the value contained in <code>rhs</code> to the value contained in <code>*this</code>. Otherwise,</li> <li>if <code>index() == j &amp;&amp; is_nothrow_move_assignable_v&lt;T_j&gt;</code>, copies the value contained in <code>rhs</code> to a temporary <code>TMP</code>, then assigns <code>std::forward&lt;T_j&gt;(TMP)</code> to the value contained in <code>*this</code>. Otherwise,</li> <li>if <code>index() == j &amp;&amp;<del> !is_nothrow_move_constructible_v&lt;T_j&gt;</del><ins> !is_pilfer_constructible_v&lt;T_j&gt;</ins></code>, assigns the value contained in <code>rhs</code> to the value contained in <code>*this</code>. Otherwise,</li> <li>copies the value contained in <code>rhs</code> to a temporary <code>TMP</code>, then destroys any value contained in <code>*this</code>. Sets <code>*this</code> to hold the same alternative index as <code>rhs</code> and initializes the value contained in <code>*this</code> as if direct-non-list-initializing an object of type <code>T_j</code> with<del> <code>std::forward&lt;T_j&gt;(TMP)</code></del> <ins> <code>std::pilfer(TMP)</code></ins>.</li> </ul> <p><em>Returns:</em> <code>*this</code>.</p> <p><em>Postconditions:</em> <code>index() == rhs.index()</code></p> <p><em>Remarks:</em> This function shall not participate in overload resolution unless <code>is_copy_constructible_v&lt;T_i&gt; &amp;&amp; is_move_constructible_v&lt;T_i&gt; &amp;&amp; is_copy_assignable_v&lt;T_i&gt;</code> is <code>true</code> for all <code>i</code>.</p> <ul> <li>If an exception is thrown during the call to <code>T_j</code>'s copy assignment, the state of the contained value is as defined by the exception safety guarantee of <code>T_j</code>'s copy assignment; <code>index()</code> will be <code>j</code>.</li> <li>If an exception is thrown during the call to <code>T_j</code>'s copy constructor (with <code>j</code> being <code>rhs.index()</code>), <code>*this</code> will remain unchanged.</li> <li>If an exception is thrown during the call to <code>T_j</code>'s move constructor, the <code>variant</code> will hold no value.</li> </ul> </blockquote> <h3><code>variant&amp; operator=(variant&amp;&amp; rhs) noexcept(<em>see below</em>);</code></h3> <blockquote> <p><em>Effects:</em> Let <code>j</code> be <code>rhs.index()</code>.</p> <ul> <li>If neither <code>*this</code> nor <code>rhs</code> holds a value, there is no effect. Otherwise</li> <li>if <code>*this</code> holds a value but <code>rhs</code> does not, destroys the value contained in <code>*this</code> and sets <code>*this</code> to not hold a value. Otherwise,</li> <li>if <code>index() == j &amp;&amp; (is_nothrow_move_assignable_v&lt;T_j&gt; ||<del> !is_nothrow_move_constructible_v&lt;T_j&gt;</del><ins> !is_pilfer_constructible_v&lt;T_j&gt;</ins>)</code>, assigns <code>std::forward&lt;T_j&gt;(get&lt;j&gt;(rhs))</code> to the value contained in <code>*this</code>. Otherwise,</li> <li><ins>If <code>!is_nothrow_move_constructible_v&lt;T_j&gt; &amp;&amp; is_pilfer_constructible_v&lt;T_j&gt;</code>, initializes a temporary <code>TMP</code> of type <code>T_j</code> from <code>std::forward&lt;T_j&gt;(get&lt;j&gt;(rhs))</code>. Destroys any value contained in <code>*this</code>. Sets <code>*this</code> to hold the same alternative index as <code>rhs</code> and initializes the value contained in <code>*this</code> as if direct-non-list-initializing an object of type <code>T_j</code> with <code>std::pilfer(TMP)</code>. Otherwise,</ins></li> <li>destroys any value contained in <code>*this</code>. Sets <code>*this</code> to hold the same alternative index as <code>rhs</code> and initializes the value contained in <code>*this</code> as if direct-non-list-initializing an object of type <code>T_j</code> with <code>std::forward&lt;T_j&gt;(get&lt;j&gt;(rhs))</code>.</li> </ul> <p><em>Returns:</em> <code>*this</code>.</p> <p><em>Remarks:</em> This function shall not participate in overload resolution unless <code>is_move_constructible_v&lt;T_i&gt; &amp;&amp; is_move_assignable_v&lt;T_i&gt;</code> is <code>true</code> for all <code>i</code>. The expression inside <code>noexcept</code> is equivalent to: <code>is_nothrow_move_constructible_v&lt;T_i&gt;</code> for all <code>i</code>.</p> <ul> <li>If an exception is thrown during the call to <code>T_j</code>'s move constructor<ins> in the last bullet</ins>, the <code>variant</code> will hold no value.</li> <li>If an exception is thrown during the call to <code>T_j</code>'s move assignment, the state of the contained value is as defined by the exception safety guarantee of <code>T_j</code>'s move assignment; <code>index()</code> will be <code>j</code>.</li> </ul> </blockquote> <p> The reason of using <code>pilfer</code> only when the type can be pilfered but not <code>noexcept</code> moved is because we are not allowed to pilfer directly from <code>rhs</code>, as there is no guarantee that outside code will not access the value afterwards. So we need to first move into a temporary, and then pilfer that temporary instead. We could do that in either case, but this would result in two moves instead of one when the type has a <code>noexcept</code> move constructor.</p> <h3><code>template &lt;size_t I, class... Args&gt; void emplace(Args&amp;&amp;... args);</code></h3> <blockquote> <p><em>Requires:</em> <code>I &lt; sizeof...(Types)</code></p> <p><em>Effects:</em></p> <ul> <li>If <code>is_nothrow_constructible_v&lt;T_I, Args&amp;&amp;...&gt; ||<del> !is_nothrow_move_constructible_v&lt;T_I&gt;</del><ins> !is_pilfer_constructible_v&lt;T_j&gt;</ins></code>, destroys the currently contained value if <code>valueless_by_exception()</code> is <code>false</code> and direct-initializes the contained value as if constructing a value of type <code>T_I</code> with the arguments <code>std::forward&lt;Args&gt;(args)...</code>. Otherwise,</li> <li>direct-initializes a temporary <code>TMP</code> of type <code>T_I</code> with the arguments <code>std::forward&lt;Args&gt;(args)...</code>, destroys the currently contained value if <code>valueless_by_exception()</code> is <code>false</code> and direct-initializes the contained value as if constructing a value of type <code>T_I</code> with the argument<del> <code>std::forward&lt;T_I&gt;(TMP)</code></del><ins> <code>std::pilfer(TMP)</code></ins>.</li> </ul> <p><em>Postcondition:</em> <code>index()</code> is <code>I</code>.</p> <p><em>Throws:</em> Any exception thrown during the initialization of the contained value.</p> <p><em>Remarks:</em> This function shall not participate in overload resolution unless <code>is_constructible_v&lt;T_I, Args&amp;&amp;...&gt;</code> is <code>true</code>. If an exception is thrown during the initialization of the contained value, the <code>variant</code> will not hold a value.</p> </blockquote> <h3><code>template &lt;size_t I, class U, class... Args&gt; void emplace(initializer_list&ltU&gt; il, Args&amp;&amp;... args);</code></h3> <blockquote> <p><em>Requires:</em> <code>I &lt; sizeof...(Types)</code></p> <p><em>Effects:</em></p> <ul> <li>If <code>is_nothrow_constructible_v&lt;T_I, initializer_list&lt;U&gt;&amp;, Args&amp;&amp;...&gt; ||<del> !is_nothrow_move_constructible_v&lt;T_I&gt;</del><ins> !is_pilfer_constructible_v&lt;T_j&gt;</ins></code>, destroys the currently contained value if <code>valueless_by_exception()</code> is <code>false</code> and direct-initializes the contained value as if constructing a value of type <code>T_I</code> with the arguments <code>il, std::forward&lt;Args&gt;(args)...</code>. Otherwise,</li> <li>direct-initializes a temporary <code>TMP</code> of type <code>T_I</code> with the arguments <code>il, std::forward&lt;Args&gt;(args)...</code>, destroys the currently contained value if <code>valueless_by_exception()</code> is <code>false</code> and direct-initializes the contained value as if constructing a value of type <code>T_I</code> with the argument<del> <code>std::forward&lt;T_I&gt;(TMP)</code></del><ins> <code>std::pilfer(TMP)</code></ins>.</li> </ul> <p><em>Postcondition:</em> <code>index()</code> is <code>I</code>.</p> <p><em>Throws:</em> Any exception thrown during the initialization of the contained value.</p> <p><em>Remarks:</em> This function shall not participate in overload resolution unless <code>is_constructible_v&lt;T_I, initializer_list&lt;U&gt;&amp;, Args&amp;&amp;...&gt;</code> is <code>true</code>. If an exception is thrown during the initialization of the contained value, the <code>variant</code> will not hold a value.</p> </blockquote> <h3><code>constexpr bool valueless_by_exception() const noexcept;</code></h3> <blockquote> <p><em>Effects:</em> Returns <code>false</code> if and only if the variant holds a value. [Note: A variant will not hold a value if an exception is thrown from the move constructor of the contained type during a type-changing assignment or emplacement. &mdash; <em>end note</em>]</p> <p><em>Remarks:</em> This function shall be <code>static</code> and always return <code>false</code> when <code><del>is_nothrow_move_constructible_v&lt;T_i&gt;</del><ins>is_pilfer_constructible_v&lt;T_i&gt;</ins></code> is <code>true</code> for all <code>i</code>. [Note: <code>static_assert(variant&lt;Types...&gt;::valueless_by_exception() == false);</code> may be used to verify that a <code>variant&lt;Types...&gt;</code> may never become valueless. &mdash; <em>end note</em>]</p> </blockquote> <h3><code>void swap(variant&amp; rhs) noexcept(<em>see below</em>);</code></h3> <blockquote> <p><em>Effects:</em><ins> Let <code>i</code> be <code>index()</code>. Let <code>j</code> be <code>rhs.index()</code>.</ins></p> <ul> <li>if <code>valueless_by_exception() &amp;&amp; rhs.valueless_by_exception()</code> no effect. Otherwise,</li> <li>if <code>index() == rhs.index()</code>, calls <code>swap(get&lt;i&gt;(*this), get&lt;i&gt;(rhs))</code><del> with <code>i</code> being <code>index()</code></del>. Otherwise,</li> <li><ins>if <code>valueless_by_exception()</code>, constructs a value of type <code>T_j</code> into <code>*this</code> from <code>std::pilfer(get&lt;j&gt;(rhs))</code>, sets <code>index()</code> to <code>j</code> and destroys the contained value of <code>rhs</code>, making it hold no value. Otherwise,</ins></li> <li><ins>if <code>rhs.valueless_by_exception()</code>, constructs a value of type <code>T_i</code> into <code>rhs</code> from <code>std::pilfer(get&lt;i&gt;(*this))</code>, sets <code>rhs.index()</code> to <code>i</code> and destroys the contained value of <code>*this</code>, making it hold no value. Otherwise,</ins></li> <li><ins>if <code>is_pilfer_constructible_v&lt;T_i&gt; &amp;&amp; is_pilfer_constructible_v&lt;T_j&gt;</code>, constructs a temporary <code>TMP</code> of type <code>T_i</code> from <code>std::pilfer(get&lt;i&gt;(*this))</code>, destroys the contained value of <code>*this</code>, constructs a value of type <code>T_j</code> into <code>*this</code> from <code>std::pilfer(get&lt;j&gt;(rhs))</code>, sets <code>index()</code> to <code>j</code>, destroys the contained value of <code>rhs</code>, constructs a value of type <code>T_i</code> into <code>rhs</code> from <code>std::pilfer(TMP)</code>, and sets <code>rhs.index()</code> to <code>i</code>. Otherwise,</ins></li> <li>exchanges values of <code>rhs</code> and <code>*this</code>.</li> </ul> <p><em>Throws:</em> Any exception thrown by <code>swap(get&lt;i&gt;(*this), get&lt;i&gt;(rhs))</code> with <code>i</code> being <code>index()</code> or <code>variant</code>'s move constructor and move assignment operator.</p> <p><em>Remarks:</em> This function shall not participate in overload resolution unless all alternative types satisfy the <code>Swappable</code> requirements (17.6.3.2). If an exception is thrown during the call to function <code>swap(get&lt;i&gt;(*this), get&lt;i&gt;(rhs))</code>, the states of the contained values of <code>*this</code> and of <code>rhs</code> are determined by the exception safety guarantee of <code>swap</code> for lvalues of <code>T_i</code> with <code>i</code> being <code>index()</code>. If an exception is thrown during the exchange of the values of <code>*this</code> and <code>rhs</code>, the states of the values of <code>*this</code> and of <code>rhs</code> are determined by the exception safety guarantee of <code>variant</code>'s move constructor and move assignment operator. <ins>The expression inside <code>noexcept</code> is <code>true</code> when <code>noexcept(swap(declval&lt;T_k&gt;(), declval&lt;T_k&gt;())) &amp;&amp; is_pilfer_constructible_v&lt;T_k&gt;</code> is <code>true</code> for all <code>k</code>, <code>false</code> otherwise.</ins></p> </blockquote> <h2>V. Never Valueless, Really</h2> <p> At this point, we have a <code>variant</code> that is never valueless for types that are either <code>noexcept</code> move constructible or pilfer constructible, which covers a large majority of the use cases. The natural next step is to dispense with <code>valueless_by_exception</code> altogether by requiring the contained types to be such. Can we afford to do so?</p> <p> What use cases demand types that are neither <code>noexcept</code> move- nor pilfer-constructible?</p> <p> First, there are the legacy C++03 types that have a copy constructor but do not have a move constructor, and for some reason, can't be changed. They can be moved, but this involves a copy, and is not <code>noexcept</code>.</p> <p> Second, there are the types that are neither copyable nor movable, such as <code>std::mutex</code>. An example of a <code>variant</code> instantiated on such types would be <code>variant&lt;std::mutex, std::recursive_mutex&gt;</code>.</p> <p> There is an easy workaround in both cases: instead of putting a prohibited type <code>T</code> into the <code>variant</code>, use <code>unique_ptr&lt;T&gt;</code> instead. <code>unique_ptr</code> is <code>noexcept</code> moveable, and the cost in our case of switching to it is a heap allocation and the need to check for <code>nullptr</code>.</p> <p> The benefit of relegating these two uncommon use cases to the dusty "use <code>unique_ptr</code>" folder is that we'll finally be able to get rid of <code>valueless_by_exception</code> altogether, thereby simplifying the specification a bit and eliminating the need for the programmers to <code>static_assert</code> that their <code>variant</code>s can't be valueless.</p> <p> For a C++17 component, this is also the conservative approach. If these two use cases turn out to be important in practice, we can later either bring back <code>valueless_by_exception</code> or provide some other way to address them, without breaking any code. If we instead provide the current, <code>valueless_by_exception</code>-possessing <code>variant</code>, we cannot at a later date take that away.</p> <p> More specifically, if we focus on <code>variant&lt;std::mutex, std::recursive_mutex&gt;</code>, we see a use case that is indeed legitimate in that it's using <code>variant</code> as if it were a slightly more convenient <code>union { std::mutex m; std::recursive_mutex rm; }</code>. However, this <code>variant</code> does not have much in common with <code>variant&lt;int, float, std::string&gt;</code>, in that the latter is Regular and the former decidedly isn't. So if we were in a situation where we already had a standard Regular, never valueless, <code>variant</code> and were faced with the need to support this "convenient <code>union</code>" use case, we would probably take a serious look at the possibility of providing a separate component that addresses this need, instead of making <code>variant</code> potentially valueless.</p> <p> The case for this change is less strong. I consider the previous two sections a strict and necessary improvement to the existing proposal (in spirit and intent, not specific wording, which may well have defects.) On the "strongly in favor" as +2 .. "strongly against" as -2 spectrum, my current position on section III would be +3, and section IV would be +2.5 <em>unless the standard library is instead changed to require <code>noexcept</code> move constructors on all of its types</em>. This section would only score about +1.7.</p> <p> Therefore, I will not provide suggested wording for the elimination of <code>valueless_by_exception</code> in this revision, although I will in a subsequent revision if discussion and straw polls provide an indication that the working groups are willing to consider such a change.</p> <hr /> <p> <em>&mdash; end</em></p> </body> </html>