id,summary,reporter,owner,description,type,status,milestone,component,version,severity,resolution,keywords,cc 13487,Error detecting is_nothrow_move_constructible & is_nothrow_move_assignable,Andrey Glebov ,Ion Gaztañaga,"The current type trait implementation of Boost.Move doesn't detect nothrow move construction or assignment. While `boost/move/detail/type_traits.hpp` defines many macros such as `BOOST_MOVE_HAS_NOTHROW_COPY`, it never defines `BOOST_MOVE_HAS_NOTHROW_MOVE` or `BOOST_MOVE_HAS_NOTHROW_MOVE_ASSIGN` for any compiler. As a result, `boost::move:detail::is_nothrow_move_constructible` and `is_nothrow_move_assignable` fallback to `boost::move_detail::is_pod::value` which is incorrect for any non-POD type. In my particular instance the result is that `boost::circular_buffer` chooses copy instead of move in `boost::move_if_noexcept()` for `std::weak_ptr` (which is nothrow move constructible and assignable), which in turn results in >10x worse performance of functions such as `boost::circular_buffer::erase()` in some conditions. It is possible to work around this by manually specializing `boost::has_nothrow_move`, 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 `libstdc++` implementation below). I propose fixing this issue by defining `BOOST_MOVE_HAS_NOTHROW_MOVE` and `BOOST_MOVE_HAS_NOTHROW_MOVE_ASSIGN` for all compilers that support move semantics. `libstdc++` seems to have the most correct and portable way of doing this - without using compiler intrinsics: {{{ #!c++ template struct __is_nt_constructible_impl : public integral_constant()...))> { }; template struct __is_nt_constructible_impl<_Tp, _Arg> : public integral_constant(declval<_Arg>()))> { }; template::value> struct __is_nothrow_move_constructible_impl; template struct __is_nothrow_move_constructible_impl<_Tp, false> : public false_type { }; template struct __is_nothrow_move_constructible_impl<_Tp, true> : public is_nothrow_constructible<_Tp, _Tp&&> { }; template struct __is_nt_assignable_impl : public integral_constant() = declval<_Up>())> { }; template::value> struct __is_nt_move_assignable_impl; template struct __is_nt_move_assignable_impl<_Tp, false> : public false_type { }; template struct __is_nt_move_assignable_impl<_Tp, true> : public is_nothrow_assignable<_Tp&, _Tp&&> { }; }}} Visual Studio 14.0's implementation uses the intrinsics `__is_nothrow_constructible(T, Args...)` and `__is_nothrow_assignable(To, From)` 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). It might also be a good idea to replace the fallback to `boost::move_detail::is_pod` with more specific and inclusive `is_trivially_copy_constructible`, `is_trivially_copy_assignable` type traits.",Bugs,new,To Be Determined,move,Boost Development Trunk,Problem,,move noexcept nothrow,