I'm trying to compile the following code:
#include <map>
#include <condition_variable>
class MyClass
{
public:
MyClass(): m_cv() {}
std::condition_variable m_cv; //just to illustrate that a copy constructor is not obvious to write
};
int main()
{
std::map<std::string,MyClass> testmap;
testmap.emplace("key",MyClass());
}
Compilation fails at the last line (emplace
method call) with a very long error that starts as follows:
error: no matching function for call to ‘std::pair, MyClass>::pair(const char [4], MyClass)
By trial and error, I have come up with the understanding that the error comes from the absence of copy constructor for MyClass
. If I add one, or else if I replace the condition variable attribute with a basic type (int
for instance), the error disappears. However I'm not sure of my analysis, and most importantly, I do not understand why a copy constructor for MyClass
is needed here.
So my question is twofold:
In C++17:
testmap.try_emplace("key");
In C++14 or older:
testmap.emplace(std::piecewise_construct, std::forward_as_tuple("key"), std::tuple<>{});
You code constructs MyClass
twice: one time you do it manually (MyClass()
), and the second time std::map
does it internally (in your case it tries to call the copy constructor).
The second constructor call isn't going anywhere, but you can change what arguments it receives, if any. So you have to get rid of the first call, and change the second call to receive no arguments, as opposed to const MyClass &
.
The arguments of .emplace()
go straight to the constructor of std::pair
. If you examine the constructors, the only one that can default-construct the second element (not counting the pair's own default constructor) seems to be the std::piecewise_construct
one.
And .try_emplace()
just uses std::piecewise_construct
internally.