std::map emplace non-movable non-copyable non-default-constructible type

Viewed 374

I want a map of a class that has no copy ctor, no move ctor, and no default ctor (I have no control over this class).

I've tried using std::map::emplace with the std::piecewise_construct and std::forward_as_tuple arguments, but it seems like the compiler is telling me that this is not possible because it tries default constructing first.

// Example program
#include <iostream>
#include <string>
#include <map>
#include <utility>
#include <tuple>

class stone
{
public:
    stone() = delete;
    stone(stone& s) = delete;
    stone(stone&& s) = delete;
    stone(const std::string& s) : str(s)
    {
    }
    std::string str;
};

int main()
{
    std::map<int, stone> m;
    m.emplace(std::piecewise_construct, std::forward_as_tuple(5), std::forward_as_tuple("asdf"));
    std::cout << "map[5]: " << m[5].str << "\n";
}

See the example with the compiler error here: http://cpp.sh/8bbwh

How can I make this work? I've tried looking at similar questions, but they don't seem to contain any answers that are useful to my very specific scenario.

2 Answers

std::map emplace non-movable non-copyable non-default-constructible type

Like this:

m.emplace(5, "asdf");

There is no need for std::piecewise_construct nor std::forward_as_tuple.


As for looking up the value, you cannot use the subscript operator because that requires the type to be default constructible - the default construction will be used when the value isn't in the map before lookup.

To lookup a non-default constructible type, you must use map::find or map::at instead. Former returns iterator to end and latter throws an exception if the mapped value does not exist.

There's no issue with the emplace operation, however, the issue is with std::map::operator[] since it requires the value_type to be default constructible. However, stone has a deleted default constructor.

Instead, you could use std::map::at which does not have that requirement:

std::cout << "map[5]: " << m.at(5).str << "\n";

Here's a demo.

Related