The following concerns are related to the suggested implementation of std::optional - see<br><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3672.html" target="_blank">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3672.html</a><br>

<a href="https://github.com/akrzemi1/Optional/blob/master/optional.hpp" target="_blank">https://github.com/akrzemi1/Optional/blob/master/optional.hpp</a><br><br>Consider the following example:<br><br><span style="font-family:courier new,monospace">    #include &quot;optional.hpp&quot;<br>

    #include &lt;iostream&gt;<br><br>    struct A<br>    {<br>        constexpr A(int &amp;x) : ref(x) {}<br>        int &amp;ref;<br>    };<br><br>    int main()<br>    {<br>        int n1 = 0, n2 = 0;<br>        std::experimental::optional&lt;A&gt; opt = A(n1);<br>

        opt.emplace(n2);<br>        opt-&gt;ref = 1;<br>        std::cout &lt;&lt; n1 &lt;&lt; &quot; &quot; &lt;&lt; n2 &lt;&lt; std::endl;<br>    }<br></span><br>Here initialization of variable opt implies initialization of union member <span style="font-family:courier new,monospace">storage_.value_</span> (which has type A). Then expression <span style="font-family:courier new,monospace">opt.emplace(n2)</span> destroys object <span style="font-family:courier new,monospace">storage_.value_</span> via explicit destructor call and creates new object by placement form of new-expression (using forwarded n2 in the new-initializer). All public functions that provide access to the stored value (operator-&gt;(), operator *(), value(), etc.), obtain pointer/reference through object expression <span style="font-family:courier new,monospace">storage_.value_</span>.<br>

<br>This is a simplified version of the above code:<br><br><span style="font-family:courier new,monospace">    #include &lt;iostream&gt;<br><br>    #define FORWARD(x) static_cast&lt;decltype(x) &amp;&amp;&gt;(x)<br><br>    template &lt;class T&gt;<br>

        union U<br>    {<br>        U(T &amp;&amp;x) : value_(x) {}<br>        unsigned char dummy_;<br>        T value_;<br>    };<br><br>    template &lt;class T&gt;<br>        struct optional<br>    {<br>        constexpr optional(T &amp;&amp;x) : storage_(FORWARD(x)) {}<br>

        template &lt;class... Params&gt;<br>            void emplace(Params &amp;&amp;... params)<br>        {<br>            storage_.value_.~T();<br>            new (&amp;storage_.value_) T(FORWARD(params)...);<br>        }<br>

<br>        U&lt;T&gt; storage_;<br>    };<br><br>    struct A<br>    {<br>        constexpr A(int &amp;x) : ref(x) {}<br>        int &amp;ref;<br>    };<br><br>    int main()<br>    {<br>        int n1 = 0, n2 = 0;<br>        optional&lt;A&gt; opt2 = A(n1);<br>

        opt2.emplace(n2);<br>        opt2.storage_.value_.ref = 1;<br>        std::cout &lt;&lt; n1 &lt;&lt; &quot; &quot; &lt;&lt; n2 &lt;&lt; std::endl;<br>    }</span><br><br>The question is: What may happen at line<br>

<br><span style="font-family:courier new,monospace">    opt-&gt;ref = 1;</span><br><br>in the former code or<br><br><span style="font-family:courier new,monospace">    </span><span style="font-family:courier new,monospace">opt2.storage_.value_.ref = 1;</span><br>
<br>in the latter (simplified) code?<br>
<br>According to N3485 - 3.8/7,<br><br>    If, after the lifetime of an object has ended and before the<br>    storage which the object occupied is reused or released, a new<br>    object is created at the storage location which the original<br>

    object occupied, a pointer that pointed to the original object, a<br>    reference that referred to the original object, or the name of the<br>    original object will automatically refer to the new object and,<br>    once the lifetime of the new object has started, can be used to<br>

    manipulate the new object, if:<br><br>    [...]<br>    — the type of the original object is not const-qualified, and, if<br>      a class type, does not contain any non-static data member whose<br>      type is const-qualified or a reference type, and<br>

    [...]<br><br>In our case the cited condition is not satisfied, because A has a non-static data member of a reference type — ref.<br><br>It looks like a compiler is free to assume that <span style="font-family:courier new,monospace">opt-&gt;ref</span> or <span style="font-family:courier new,monospace">opt2.storage_.value_.ref</span> still refers to n1 (as if the accessed ref would be member of the old object) rather than n2 (to which new ref is supposed to refer). Is this interpretation correct? What else may happen? If the aforementioned implementation of std::optional is unreliable, how would you suggest to improve it?<br>