Std :: map emplace ends up with an explicit constructor

class A {
public:
    explicit A(int x) {}
};

vector<A> v;
v.push_back(1);  // compiler error since no implicit constructor
v.emplace_back(1); // calls explicit constructor

      

Above is the description by David Stone. I don't understand why the call is emplace_back

an explicit constructor? I don't see anything in the C ++ standard that makes this legal. It was only after listening to David Stone's youtube video, I found out about it.

Now I am trying the same with std::map

.

map<int, A> m;
m.insert(pair<int, A>(1, 2)); // compiler error since no implicit constructor
m.emplace(1, 2); // compiler error since no implicit constructor

      

Why emplace

doesn't it work? If it emplace_back

can call the constructor explicitly, why emplace

doesn't it do the same?

+3


source to share


3 answers


emplace

method inserts elements by explicitly calling the constructor with placement new operator

. When entering into a map, you need separate forward arguments to construct the key and value.



m.emplace
(
    ::std::piecewise_construct // special to enable forwarding
,   ::std::forward_as_tuple(1) // arguments for key constructor
,   ::std::forward_as_tuple(2) // arguments for value constructor
);

      

+3


source


The functions emplace

call your constructor as described in the standard at http://eel.is/c++draft/container.requirements.general#15.5

T

EmplaceConstructible

in X

from args

, for zero or more arguments args

means that the following expression is well-formed:

allocator_traits<A>::construct(m, p, args)

This means it ultimately comes down to your distributor. Considering the link on what this means we can check http://en.cppreference.com/w/cpp/memory/allocator_traits/construct

We see that if the allocator has no construct member function or if it does std::allocator

, then the call is equivalent to



::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)

For, std::map<int, A>

type T

in your expression is std::pair<int const, A>

and args...

is 1, 2

. Therefore, to know if your challenge is well-formed emplace

, we just need to decide if the challenge is valid std::pair<int const, A>(1, 2)

. For that, we'll look at the documentation for std::pair

: http://en.cppreference.com/w/cpp/utility/pair/pair

The specified constructor is listed as /*EXPLICIT*/ constexpr pair( const T1& x, const T2& y );

(assuming C ++ 17). In other words, it is like calling a regular function that takes int const &

as the first argument and A const &

as the second. A

is clearly constructive int

, so your call is poorly formed. The call emplace

only saves you from explicit

on any objects that you directly create, which is simple in this case std::pair

, and not any arguments of that type.

+2


source


m.insert(std::pair<int, A>(1, 2))

compiles, I don't know why it doesn't compile for you. Maybe you forgot the flag -std=c++11

? This is because the constructor std::pair

explicitly calls the constructor when it copies elements to first

and second

.

If you want to insert in std::map

, you need to specify the key and value in std::pair

. You can use std::make_pair

for this:

m.emplace(std::make_pair(1, 2));

      

This compiles as the pair will be built in place in the key / value pair and the explicit constructor will be called.

+1


source







All Articles