
El 23/05/2025 a las 3:13, David Bien via Boost escribió:
I noticed the specialized emplace() right away - it looked weird so I thought about it for a bit:
template<typename... Args> BOOST_FORCEINLINE void emplace(Args&&... args) { insert(detail::allocator_constructed<allocator_type,value_type>{ get_allocator(),std::forward<Args>(args)...}.value()); } template< typename U, typename std::enable_if< std::is_same<T,detail::remove_cvref_t<U>>::value>::type* =nullptr
BOOST_FORCEINLINE void emplace(U&& x) { insert(x); /* avoid value_type construction */ }
Given T t; So, the emplace( std::move(t)) will call emplace(U&&), which doesn’t move anything out of the value x, cuz insert(const&). emplace(t) will call the emplace(Args&&… args) because emplace(U&&) can’t accept a const T& - and will make a copy of t before calling insert().
No, emplace(t) also selects template< typename U, typename std::enable_if< std::is_same<T,detail::remove_cvref_t<U>>::value>::type* =nullptr > BOOST_FORCEINLINE void emplace(U&& x) { insert(x); /* avoid value_type construction */ } So, no copy of t is incurred. U&& is a so-called universal reference that matches everything, including const T&.
I get why it was done, but I find it to be obfuscating or confusing. You could as well just declare the emplace for T as emplace(const U&) (which also looks weird) and a copy wouldn’t be made but it will still accept the call emplace(std::move(t)).
I think ridding emplace entirely is probably the best move - we aren’t emplacing anything in reality.
That’s my two cents, and also not really a review since I didn’t spend enough time for a real review. Hopefully I’m not annoying anyone - lol.
On the contrary, I'm happy the review is producing such interesting conversations. Joaquin M Lopez Munoz