Can Vector Initialization with Move-Only Types be Achieved?
The question arises when attempting to initialize a vector with unique pointers, a move-only type. When encountering code like this:
#include <vector> #include <memory> using move_only = std::unique_ptr<int>; std::vector<move_only> v { move_only(), move_only(), move_only() };
GCC 4.7 endeavors to copy the unique pointers from the initializer list, resulting in a copy attempt that isn't permissible due to the move-only nature of std::unique_ptr.
GCC's Approach: Is it Flawed?
GCC's intention to copy the pointers is correct, considering that unique pointers are non-copyable. However, the method it employs, copying from the initializer list, triggers the deleted copy constructor.
Alternative Solution Using Make Move Iterator
To handle move-only types in vector initialization, a preferred approach involves utilizing make move iterators:
#include <iterator> #include <vector> #include <memory> int main(){ using move_only = std::unique_ptr<int>; move_only init[] = { move_only(), move_only(), move_only() }; std::vector<move_only> v{std::make_move_iterator(std::begin(init)), std::make_move_iterator(std::end(init))}; }
The iterators obtained from make move iterators facilitate the movement of elements upon dereferencing, resolving the problem with copying.
Alternative Solution Using Template Wrappers
Another approach involves employing template wrappers with rvalue reference semantics:
// Helper type for converting rvalues to lvalues template<class T> struct rref_wrapper { explicit rref_wrapper(T&& v) : _val(std::move(v)) {} explicit operator T() const{ return T{ std::move(_val) }; } private: T&& _val; }; // Helper function to convert rvalues to rref_wrappers template<class T> typename std::enable_if< !std::is_lvalue_reference<T>::value, rref_wrapper<T> >::type rref(T&& v){ return rref_wrapper<T>(std::move(v)); } // Helper function to delete lvalue references template<class T> void rref(T&) = delete;
While this solution provides a way to conceptually convert rvalues to lvalues, it is crucial to exercise caution due to its volatility. A more concise initialization can be achieved through a two-step process:
std::initializer_list<rref_wrapper<move_only>> il{ rref(move_only()), rref(move_only()), rref(move_only()) }; std::vector<move_only> v(il.begin(), il.end());
The above is the detailed content of How Can I Initialize a Vector with Move-Only Types in C ?. For more information, please follow other related articles on the PHP Chinese website!