Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::unordered_map gives error when inserting using emplace function

Tags:

c++

I'm getting this weird error when inserting an element into std::unordered_map using emplace function but not if I use operator[] function overload. This is my code:

#include <iostream>
#include <unordered_map>
#include <memory>

class B {
public:
    B() = default;
    ~B() = default; 
};

class A {
public:
    A() = default;
    ~A() = default;
    
    std::unique_ptr<B> b_ptr;
};

int main() {
    std::unordered_map<std::string, A> mp;
    // mp.emplace("abc", A()); // gives compiler here
    auto& a = mp["def"];
}

I'm getting huge error print when compiled. This is a short note of error: template argument deduction/substitution failed

like image 748
Harry Avatar asked Sep 29 '21 14:09

Harry


1 Answers

When you use emplace like mp.emplace("abc", A()); what you are doing is creating a temporary A, and that object is then copied/moved into the object that emplace is going to construct. When you did ~A() = default; in the class, that gets rid of the compiler supplied default move constructor, and the copy constructor is implicitly deleted because std::unique_ptr can't be copied so the A() can't be moved or copied into the object emplace is going to create.

You can fix this by using the std::piecewise_construct taged version of emplace to forward the parts of the key value pair to emplace like

mp.emplace(std::piecewise_construct,    // call the piecewise_construct overload
          std::forward_as_tuple("abc"), // forwards "abc" to the key
          std::forward_as_tuple());     // forwards nothing to the value so it can be default constructed
          

or you could just add a move constructor to A using

A(A&&) = default;

so that emplace can move the A() you created in main into mp.

like image 70
NathanOliver Avatar answered Nov 04 '22 12:11

NathanOliver