Boost C++ Libraries: Ticket #11132: Boost.Variant's boost::recursive_wrapper missing noexcept specifier on move constructor https://svn.boost.org/trac10/ticket/11132 <p> Using a sequence container of recursive variant, like std::vector&lt;recursive_variant_&gt;, results in the variant type not being movable. </p> <p> Example: </p> <pre class="wiki">#include &lt;boost/variant.hpp&gt; #include &lt;vector&gt; using namespace std; using namespace boost; struct foo { foo() = default; foo(foo&amp;&amp;) noexcept = default; foo(foo const&amp;) = delete; }; int main() { typedef make_recursive_variant&lt; foo, vector&lt;recursive_variant_&gt; &gt;::type variant_type; vector&lt;variant_type&gt; value; value.emplace_back(); variant_type other = std::move(value); } </pre><p> This errors at the move assignment because variant_type is not movable. The reason it is not movable is because boost::recursive_wrapper's move constructor is not marked as noexcept, which is a requirement for vector to enable move semantics. </p> <p> Currently boost::recursive_wrapper's move constructor is not marked noexcept because it allocates a new T when being moved. </p> <p> I propose that boost::recursive_wrapper be changed to store a shared_ptr&lt;T&gt; instead of T* so that, when moved, we move the shared_ptr, which is a noexcept operation. For the overload that constructs by T&amp;&amp;, we can leave as not specifying noexcept and construct with: </p> <pre class="wiki">_p(new T(detail::variant::move(operand))) </pre><p> The copy semantics of boost::recursive_wrapper can be left as-is. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/11132 Trac 1.4.3 peterhuene@… Fri, 20 Mar 2015 19:49:50 GMT summary changed https://svn.boost.org/trac10/ticket/11132#comment:1 https://svn.boost.org/trac10/ticket/11132#comment:1 <ul> <li><strong>summary</strong> <span class="trac-field-old">Boost.Variant's boost::recursive_wrapper missing noexcept specified on move constructor</span> → <span class="trac-field-new">Boost.Variant's boost::recursive_wrapper missing noexcept specifier on move constructor</span> </li> </ul> Ticket peterhuene@… Sat, 21 Mar 2015 19:28:18 GMT <link>https://svn.boost.org/trac10/ticket/11132#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11132#comment:2</guid> <description> <p> Actually, upon more thought, there's no reason to use shared_ptr&lt;T&gt; here at all. </p> <pre class="wiki">boost::recursive_wrapper(boost::recursive_wrapper&amp;&amp; operand) noexcept </pre><p> This simply needs to take ownership of operand's _p so that operand doesn't delete it. No shared_ptr required (silly suggestion). </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Steven Watanabe</dc:creator> <pubDate>Sat, 21 Mar 2015 19:55:45 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11132#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11132#comment:3</guid> <description> <p> I'm pretty sure that we discussed this implementation of move construction on the developer's list a couple of years ago, and decided that it was incorrect, because it introduces an additional moved-from state. </p> </description> <category>Ticket</category> </item> <item> <author>peterhuene@…</author> <pubDate>Sun, 22 Mar 2015 01:49:37 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11132#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11132#comment:4</guid> <description> <p> Is invoking T's move constructor when the wrapper is moved really more important than maintaining move semantics for vector&lt;recursive_variant_&gt; and, by extension, the entire variant type? </p> <p> I get that the wrapper is supposed to be as transparent as possible to the user of the recursive variant (i.e. T's move constructor would normally be invoked on move), but, in my opinion, the intent of move semantics is still being adhered to if _p is moved instead of a new T allocated and then moved into. </p> <p> To put it another way: I think forcing copy semantics for recursive variants with sequence containers (for the sake of complete wrapper transparency?) to be unreasonably burdensome for users expecting their variants to be efficiently movable. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Antony Polukhin</dc:creator> <pubDate>Mon, 22 Jun 2015 19:59:39 GMT</pubDate> <title>owner, status changed https://svn.boost.org/trac10/ticket/11132#comment:5 https://svn.boost.org/trac10/ticket/11132#comment:5 <ul> <li><strong>owner</strong> changed from <span class="trac-author">ebf</span> to <span class="trac-author">Antony Polukhin</span> </li> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> </ul> <p> This issue has been discussed a lot. After a very long discussion it was decided to leave <code>recursive_wrapper</code> as is. </p> <p> Personaly I dislike the existing approach, but agree that it must stay as is. </p> <p> The only way that I could help you, is to show some possible workarounds. Here's a workaround for std::vectors that support incomplete/forward declared types (fastest possible solution): </p> <pre class="wiki">#include &lt;boost/variant.hpp&gt; #include &lt;vector&gt; using namespace std; using namespace boost; struct foo { foo() = default; foo(foo&amp;&amp;) noexcept = default; foo(foo const&amp;) = delete; }; struct variant_type: boost::variant&lt;foo, vector&lt;variant_type&gt; &gt; { typedef boost::variant&lt;foo, vector&lt;variant_type&gt; &gt; base_t; variant_type() = default; template &lt;class T&gt; variant_type(T&amp;&amp; v) : base_t(std::forward&lt;T&gt;(v)) {} }; int main() { vector&lt;variant_type&gt; value; value.emplace_back(); variant_type other = std::move(value); } </pre><p> This example must work on popular STL implementations. </p> Ticket Antony Polukhin Wed, 18 Jan 2017 19:48:30 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/11132#comment:6 https://svn.boost.org/trac10/ticket/11132#comment:6 <ul> <li><strong>status</strong> <span class="trac-field-old">assigned</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">wontfix</span> </li> </ul> Ticket