-1

I'm developing a basic(low-level) c++11 library for my team. Now I'm trying to develop a custom container.

template<typename T1, typename T2>
class CustomMap {
public:
    void insert(const std::map<T1, T2>& container) { mp_.insert(container.begin(), container.end()); }
    void emplace(std::map<T1, T2>&& container) { mp_.emplace(container.begin(), container.end()); }

private:
    std::map<T1, T2> mp_;
};

int main() {
    CustomMap<int, int> mp;
    std::map<int, int> mm;
    mm[1] = 2;
    mp.emplace(std::move(mm)); // ERROR

    return 0;
}

It doesn't seem that std::map::emplace can accept two parameters: begin and end?

So why can std::map::insert accept begin and end but std::map::emplace can't?

In the function void emplace of my code, I have to use a loop?

for (auto && ele : container) {
    mp_.emplace(ele);
}
Yves
  • 11,597
  • 17
  • 83
  • 180
  • 3
    The arguments you pass to `emplace` need to be able to construct a `std::pair` because they're just forwarded directly there. `insert` specifically has an overload allowing you to insert the contents of a range, but `emplace` is for constructing a single element in-place. – Nathan Pierson Aug 14 '21 at 04:25
  • It's worth reading about the functions you're asking about. – sweenish Aug 14 '21 at 04:40
  • @sweenish I've read `std::map::emplace`. But it didn't tell me why it is designed like this. Why doesn't standard overload this function with two parameters of iterator type? – Yves Aug 14 '21 at 04:58
  • The simple answer is that it's not what the function was designed to do. What you're wanting is nowhere in the neighborhood of the intent of emplace. You say you read about it, but it doesn't seem like it at all. – sweenish Aug 14 '21 at 13:54

1 Answers1

3

emplace takes arguments to pass to the constructor of the contained elements of the sequence. In this case, it's a std::pair<const Key, Value>, so when you call emplace the arguments you provide are passed to the constructor of a std::pair. As two iterators are not valid arguments, it won't compile.

These examples are from cppreference, to give you ideas of how emplace is actually used:

std::map<std::string, std::string> m;

// uses pair's move constructor
m.emplace(std::make_pair(std::string("a"), std::string("a")));

// uses pair's converting move constructor
m.emplace(std::make_pair("b", "abcd"));

// uses pair's template constructor
m.emplace("d", "ddd");

// uses pair's piecewise constructor
m.emplace(std::piecewise_construct,
          std::forward_as_tuple("c"),
          std::forward_as_tuple(10, 'c'));
Chris Uzdavinis
  • 6,022
  • 9
  • 16
  • OK. Still, I don't know why Standard doesn't overload the function emplace with two iterators... Since `insert` can insert from begin to end, why can't we `emplace` from begin to end. – Yves Aug 14 '21 at 05:00
  • @Yves Supposing `emplace` did take a pair of iterators, what behavior would you expect it to have that would be any different from `insert`? – Chris Uzdavinis Aug 14 '21 at 05:04