【问题标题】:Emplace a std::array of non-movable objects that cannot be default constructed放置一个不能默认构造的不可移动对象的 std::array
【发布时间】:2022-01-13 03:40:28
【问题描述】:

我有一个包含std::mutex 的类,因此它不可移动或复制。

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

我可以轻松地将这个对象添加到这张地图中:

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

但我想使用std::array 来保存其中的几个:

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

如果MyObject 是可移动的,那么我可以这样做:

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

但是当MyObject 不可移动时,这不起作用(如预期的那样)。我不能回退到分段构造,因为 std::array 不能从 3 个字符串的元组构造。

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

有没有办法在地图中的适当位置构造一个std::array 的不可移动对象?

我将这些问题用作参考。有没有办法组合答案?

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

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

我也试过了:

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

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

认为列表应该是可移动的,但这也行不通。

【问题讨论】:

  • 您可以将std::thread 包裹在std::unique_ptr 中以使其可移动。
  • 顺便说一句,第一个Foo 是不是意味着MyObject
  • 谢谢!我编辑了问题以解决命名问题。
  • @kiner_shah 我不想实际移动包含互斥锁的对象。它只会存在于包含它的地图中。我只需要在施工期间把它搬进去。

标签: c++ c++11 containers emplace


【解决方案1】:

使用自定义数组,您可以这样做

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

【讨论】:

  • 我稍微修改了一下。以前我使用的是:using MapEntry = std::array&lt;MyObject, 3&gt;; 我可以将其换成:struct MapEntry : std::array&lt;MyObject, 3&gt; { template &lt;typename... Us&gt; LeaderMapEntry(Us&amp;&amp;... args) : std::array&lt;MyObject, 3&gt;{ std::forward&lt;Us&gt;(args)...} {} }; 并且它有效!
  • 这实际上很酷,并且完全按照我想要的方式转发参数。非常感谢!
猜你喜欢
  • 2018-10-04
  • 1970-01-01
  • 1970-01-01
  • 2016-04-07
  • 1970-01-01
  • 2016-11-05
  • 2012-07-30
  • 2023-04-08
相关资源
最近更新 更多