Boost C++ Libraries: Ticket #13487: Error detecting is_nothrow_move_constructible & is_nothrow_move_assignable https://svn.boost.org/trac10/ticket/13487 <p> The current type trait implementation of Boost.Move doesn't detect nothrow move construction or assignment. </p> <p> While <code>boost/move/detail/type_traits.hpp</code> defines many macros such as <code>BOOST_MOVE_HAS_NOTHROW_COPY</code>, it never defines <code>BOOST_MOVE_HAS_NOTHROW_MOVE</code> or <code>BOOST_MOVE_HAS_NOTHROW_MOVE_ASSIGN</code> for any compiler. As a result, <code>boost::move:detail::is_nothrow_move_constructible</code> and <code>is_nothrow_move_assignable</code> fallback to <code>boost::move_detail::is_pod&lt;T&gt;::value</code> which is incorrect for any non-POD type. </p> <p> In my particular instance the result is that <code>boost::circular_buffer</code> chooses copy instead of move in <code>boost::move_if_noexcept()</code> for <code>std::weak_ptr</code> (which is nothrow move constructible and assignable), which in turn results in &gt;10x worse performance of functions such as <code>boost::circular_buffer::erase()</code> in some conditions. It is possible to work around this by manually specializing <code>boost::has_nothrow_move&lt;std::weak_ptr&gt;</code>, but this is not a practical workaround. Another workaround would be to define the trait macros via compiler switches but this is clearly not the intended behavior as all other macros are defined in the header, and it might not be practical as some helper traits may need to be defined too (see <code>libstdc++</code> implementation below). </p> <p> I propose fixing this issue by defining <code>BOOST_MOVE_HAS_NOTHROW_MOVE</code> and <code>BOOST_MOVE_HAS_NOTHROW_MOVE_ASSIGN</code> for all compilers that support move semantics. <code>libstdc++</code> seems to have the most correct and portable way of doing this - without using compiler intrinsics: </p> <div class="wiki-code"><div class="code"><pre> <span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">_Tp</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">_Args</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="nl">__is_nt_constructible_impl</span> <span class="p">:</span> <span class="k">public</span> <span class="n">integral_constant</span><span class="o">&lt;</span><span class="kt">bool</span><span class="p">,</span> <span class="k">noexcept</span><span class="p">(</span><span class="n">_Tp</span><span class="p">(</span><span class="n">declval</span><span class="o">&lt;</span><span class="n">_Args</span><span class="o">&gt;</span><span class="p">()...))</span><span class="o">&gt;</span> <span class="p">{</span> <span class="p">};</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">_Tp</span><span class="p">,</span> <span class="k">typename</span> <span class="n">_Arg</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">__is_nt_constructible_impl</span><span class="o">&lt;</span><span class="n">_Tp</span><span class="p">,</span> <span class="n">_Arg</span><span class="o">&gt;</span> <span class="o">:</span> <span class="k">public</span> <span class="n">integral_constant</span><span class="o">&lt;</span><span class="kt">bool</span><span class="p">,</span> <span class="k">noexcept</span><span class="p">(</span><span class="k">static_cast</span><span class="o">&lt;</span><span class="n">_Tp</span><span class="o">&gt;</span><span class="p">(</span><span class="n">declval</span><span class="o">&lt;</span><span class="n">_Arg</span><span class="o">&gt;</span><span class="p">()))</span><span class="o">&gt;</span> <span class="p">{</span> <span class="p">};</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">_Tp</span><span class="p">,</span> <span class="kt">bool</span> <span class="o">=</span> <span class="n">__is_referenceable</span><span class="o">&lt;</span><span class="n">_Tp</span><span class="o">&gt;::</span><span class="n">value</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">__is_nothrow_move_constructible_impl</span><span class="p">;</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">_Tp</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">__is_nothrow_move_constructible_impl</span><span class="o">&lt;</span><span class="n">_Tp</span><span class="p">,</span> <span class="nb">false</span><span class="o">&gt;</span> <span class="o">:</span> <span class="k">public</span> <span class="n">false_type</span> <span class="p">{</span> <span class="p">};</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">_Tp</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">__is_nothrow_move_constructible_impl</span><span class="o">&lt;</span><span class="n">_Tp</span><span class="p">,</span> <span class="nb">true</span><span class="o">&gt;</span> <span class="o">:</span> <span class="k">public</span> <span class="n">is_nothrow_constructible</span><span class="o">&lt;</span><span class="n">_Tp</span><span class="p">,</span> <span class="n">_Tp</span><span class="o">&amp;&amp;&gt;</span> <span class="p">{</span> <span class="p">};</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">_Tp</span><span class="p">,</span> <span class="k">typename</span> <span class="n">_Up</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="nl">__is_nt_assignable_impl</span> <span class="p">:</span> <span class="k">public</span> <span class="n">integral_constant</span><span class="o">&lt;</span><span class="kt">bool</span><span class="p">,</span> <span class="k">noexcept</span><span class="p">(</span><span class="n">declval</span><span class="o">&lt;</span><span class="n">_Tp</span><span class="o">&gt;</span><span class="p">()</span> <span class="o">=</span> <span class="n">declval</span><span class="o">&lt;</span><span class="n">_Up</span><span class="o">&gt;</span><span class="p">())</span><span class="o">&gt;</span> <span class="p">{</span> <span class="p">};</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">_Tp</span><span class="p">,</span> <span class="kt">bool</span> <span class="o">=</span> <span class="n">__is_referenceable</span><span class="o">&lt;</span><span class="n">_Tp</span><span class="o">&gt;::</span><span class="n">value</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">__is_nt_move_assignable_impl</span><span class="p">;</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">_Tp</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">__is_nt_move_assignable_impl</span><span class="o">&lt;</span><span class="n">_Tp</span><span class="p">,</span> <span class="nb">false</span><span class="o">&gt;</span> <span class="o">:</span> <span class="k">public</span> <span class="n">false_type</span> <span class="p">{</span> <span class="p">};</span> <span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">_Tp</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">__is_nt_move_assignable_impl</span><span class="o">&lt;</span><span class="n">_Tp</span><span class="p">,</span> <span class="nb">true</span><span class="o">&gt;</span> <span class="o">:</span> <span class="k">public</span> <span class="n">is_nothrow_assignable</span><span class="o">&lt;</span><span class="n">_Tp</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">_Tp</span><span class="o">&amp;&amp;&gt;</span> <span class="p">{</span> <span class="p">};</span> </pre></div></div><p> Visual Studio 14.0's implementation uses the intrinsics <code>__is_nothrow_constructible(T, Args...)</code> and <code>__is_nothrow_assignable(To, From)</code> that are passed an rvalue-reference as the second argument to detect move operations. Sadly, I can't seem to find any documentation on these intrinsics so it might be better to stick to pure C++ for all compilers (or maybe i'm just not looking in the right places). </p> <p> It might also be a good idea to replace the fallback to <code>boost::move_detail::is_pod&lt;T&gt;</code> with more specific and inclusive <code>is_trivially_copy_constructible&lt;T&gt;</code>, <code>is_trivially_copy_assignable&lt;T&gt;</code> type traits. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/13487 Trac 1.4.3 Andrey Glebov <andrey458641387@…> Mon, 19 Mar 2018 11:40:38 GMT <link>https://svn.boost.org/trac10/ticket/13487#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/13487#comment:1</guid> <description> <p> Note on the <code>libstdc++</code> implementation of <code>is_nothrow_move_assignable</code>: it actually also contains: </p> <div class="wiki-code"><div class="code"><pre> <span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">_Tp</span><span class="p">,</span> <span class="k">typename</span> <span class="n">_Up</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="nl">is_nothrow_assignable</span> <span class="p">:</span> <span class="k">public</span> <span class="n">__and_</span><span class="o">&lt;</span><span class="n">is_assignable</span><span class="o">&lt;</span><span class="n">_Tp</span><span class="p">,</span> <span class="n">_Up</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">__is_nt_assignable_impl</span><span class="o">&lt;</span><span class="n">_Tp</span><span class="p">,</span> <span class="n">_Up</span><span class="o">&gt;&gt;</span> <span class="p">{</span> <span class="p">};</span> </pre></div></div><p> where <code>is_assignable&lt;_Tp, _Up&gt;</code> is implemented in terms of the intrinsic <code>__is_assignable(To, From)</code>. This shouldn't be an issue though since that intrinsic seems to be supplied by most compilers. </p> </description> <category>Ticket</category> </item> </channel> </rss>