Home > Net >  Emplace a std::array of non-movable objects that cannot be default constructed
Emplace a std::array of non-movable objects that cannot be default constructed

Time:12-09

I have a class that contains a std::mutex so it is not movable or copiable.

struct MyObject {
  MyObject(std::string s_) : s(s_) {};
  std::mutex lock;
  std::thread worker;
  std::string s;
};

I can easily add this object to this map:

 std::map<int, MyObject> my_map;
 my_map.emplace(std::piecewise_construct, 
                std::forward_as_tuple(5),
                std::forward_as_tuple("string0"));

But I would like to use a std::array to hold several of them like such:

std::map<int, std::array<MyObject, 3>> my_map;

If MyObject is movable, then I can do:

my_map.emplace(4, {MyObject("string0"), MyObject("string1"), MyObject("string2")});

but this doesn't work (as expected) when the MyObject isn't movable. I can't fall back to piecewise construction since the std::array cannot be constructed from a tuple of 3 strings.

 my_map.emplace(std::piecewise_construct, 
                std::forward_as_tuple(4),
                std::forward_as_tuple("string0", "string1", "string2"));

Is there a way to construct a std::array of non-moveable objects in place in the map?

I'm using these questions as a reference. Is there a way to combine the answers?

emplace and unordered_map<?, std::array<?, N>>

How to allocate a non-copyable and non-movable object into std::map?

I've also tried:

std::array<MyObject, 3> list = {
  MyObject("string0"),
  MyObject("string1"),
  MyObject("string2")
};

my_map.emplace(4, std::move(list));

with the idea that the list should be moveable, but this also does not work.

CodePudding user response:

With custom array, you might do

template <typename T, std::size_t N>
struct MyArray
{
    template <typename... Us>
    MyArray(Us&&... args) : arr{ std::forward<Us>(args)...} {}

    std::array<T, N> arr;
};

void foo()
{
    std::map<int, MyArray<MyObject, 3>> my_map;
    my_map.emplace(std::piecewise_construct,
                   std::forward_as_tuple(4),
                   std::forward_as_tuple(std::string("string0"),
                                         std::string("string1"),
                                         std::string("string2")));
}

Demo

  • Related