Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ map brace initialization and unique ptr

Why can't I use map's braces initialization with unique_ptr?

Edit: I use gcc 7.2 in c++17 mode.

I can create and insert into unordered map using make_pair and the [] operator.

std::unordered_map<std::string, std::unique_ptr<A>> map;

map.insert(std::make_pair("hello",std::make_unique<A>()));
map["foo"] = std::make_unique<A>();

But I can't figure out why it fails when using braces.

map.insert({"foo", std::make_unique<A>()}); // Error

error: use of deleted function ‘std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&)

like image 673
Laurent Zubiaur Avatar asked Sep 14 '25 12:09

Laurent Zubiaur


1 Answers

Since C++11, associative container insertion requires either copy-costructible lvalues or move-insertable mutable rvalues. So, there's no problem invoking insert() along with make_pair() as you do: the latter constructs a pair<const char[],unique_ptr> that is used to initialize a value_type rvalue.

The problem with the brace initialization is that (until C++17) the value_type const& overload gets preferred (because there's no proper value_type&& overload), hence a copy is requested and an error is raised.

Indeed, note that both forms compile in gcc trunk and clang 5(with libc++) in c++17 mode.


More precisely, from C++11 on, the relevant insert semantic requirements read

[unord.req] If t is a non-const rvalue expression, value_type shall be MoveInsertable into X; otherwise, value_type shall be CopyInsertable into X.

is the actual members specification where things differ; until C++17, we have:

pair<iterator, bool> insert(const value_type& obj);
template <class P> pair<iterator, bool> insert(P&& obj);
...

where the generic overload is SFINAE constrained to std::is_constructible<value_type, P&&>::value. Clearly, using a braced-init-list will select the const& overload here (note: there's also an initializer_list overload, but it does not apply to the OP case).

Instead, in C++17 we also have

pair<iterator, bool> insert(value_type&& obj);
like image 132
Massimiliano Janes Avatar answered Sep 16 '25 03:09

Massimiliano Janes