<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 3585: Variant converting assignment with immovable alternative</title>
<meta property="og:title" content="Issue 3585: Variant converting assignment with immovable alternative">
<meta property="og:description" content="C++ library issue. Status: C++23">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue3585.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#C++23">C++23</a> status.</em></p>
<h3 id="3585"><a href="lwg-defects.html#3585">3585</a>. Variant converting assignment with immovable alternative</h3>
<p><b>Section:</b> 22.6.3.4 <a href="https://wg21.link/variant.assign">[variant.assign]</a> <b>Status:</b> <a href="lwg-active.html#C++23">C++23</a>
 <b>Submitter:</b> Barry Revzin <b>Opened:</b> 2021-09-01 <b>Last modified:</b> 2023-11-22</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View other</b> <a href="lwg-index-open.html#variant.assign">active issues</a> in [variant.assign].</p>
<p><b>View all other</b> <a href="lwg-index.html#variant.assign">issues</a> in [variant.assign].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++23">C++23</a> status.</p>
<p><b>Discussion:</b></p>
<p>
Example originally from <a href="https://stackoverflow.com/q/68998153/2069064">StackOverflow</a> but with a more reasonable example from Tim Song:
</p>
<blockquote><pre>
#include &lt;variant&gt;
#include &lt;string&gt;

struct A {
  A() = default;
  A(A&amp;&amp;) = delete;
};

int main() {
  std::variant&lt;A, std::string&gt; v;
  v = "hello";
}
</pre></blockquote>
<p>
There is implementation divergence here: libstdc++ rejects, libc++ and msvc accept.
<p/>
22.6.3.4 <a href="https://wg21.link/variant.assign">[variant.assign]</a> bullet (13.3) says that if we're changing the alternative in assignment 
and it is not the case that the converting construction won't throw (as in the above), then "Otherwise, 
equivalent to <code>operator=(variant(std::forward&lt;T&gt;(t)))</code>." That is, we defer to move assignment.
<p/>
<code>variant&lt;A, string&gt;</code> isn't move-assignable (because <code>A</code> isn't move constructible). Per 
the wording in the standard, we have to reject this. libstdc++ follows the wording of the standard.
<p/>
But we don't actually have to do a full move assignment here, since we know the situation we're in is 
changing the alternative, so the fact that <code>A</code> isn't move-assignable shouldn't matter. libc++ and 
msvc instead do something more direct, allowing the above program.
</p>

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

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

<p><i>[2021-10-14 Approved at October 2021 virtual plenary. Status changed: Voting &rarr; WP.]</i></p>



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

<ol>
<li><p>Modify 22.6.3.4 <a href="https://wg21.link/variant.assign">[variant.assign]</a> as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting note:</i> This should cover the case that we want to cover: that if construction of <code>T<sub><i>j</i></sub></code> 
from <code>T</code> throws, we haven't yet changed any state in the variant.]
</p>
</blockquote>

<blockquote>
<pre>
template&lt;class T&gt; constexpr variant&amp; operator=(T&amp;&amp; t) noexcept(<i>see below</i>);
</pre>
<blockquote>
<p>
-11- Let <code>T<sub><i>j</i></sub></code> be a type that is determined as follows: build an imaginary function 
<code><i>FUN</i>(T<sub><i>i</i></sub>)</code> for each alternative type <code>T<sub><i>i</i></sub></code> for which 
<code>T<sub><i>i</i></sub> x[] = {std::forward&lt;T&gt;(t)};</code> is well-formed for some invented variable 
<code>x</code>. The overload <code><i>FUN</i>(T<sub><i>j</i></sub>)</code> selected by overload resolution for the 
expression <code><i>FUN</i>(std::forward&lt;T&gt;(t))</code> defines the alternative <code>T<sub><i>j</i></sub></code> 
which is the type of the contained value after assignment.
<p/>
-12- <i>Constraints:</i> [&hellip;]
<p/>
-13- <i>Effects:</i>
</p>
<ol style="list-style-type: none">
<li><p>(13.1) &mdash; If <code>*this</code> holds a <code>T<sub><i>j</i></sub></code>, assigns <code>std::forward&lt;T&gt;(t)</code> 
to the value contained in <code>*this</code>.</p></li>
<li><p>(13.2) &mdash; Otherwise, if <code>is_nothrow_constructible_v&lt;T<sub><i>j</i></sub>, T&gt; || 
!is_nothrow_move_constructible_v&lt;T<sub><i>j</i></sub>&gt;</code> is <code>true</code>, equivalent to 
<code>emplace&lt;<i>j</i>&gt;(std::forward&lt;T&gt;(t))</code>.</p></li>
<li><p>(13.3) &mdash; Otherwise, equivalent to 
<code><del>operator=(variant(std::forward&lt;T&gt;(t)))</del><ins>emplace&lt;<i>j</i>&gt;(T<sub><i>j</i></sub>(std::forward&lt;T&gt;(t)))</ins></code>.</p></li>
</ol>
</blockquote>
</blockquote>
</li>
</ol>





</body>
</html>
