不能用带有特定构造函数的对象来创建由不可移动、不可拷贝对象组成的std::array

编程语言 2026-07-09

我想创建一个含有27个不可移动、不可拷贝对象的数组,然后对它们使用普通引用。

https://godbolt.org/z/zYhrTxK6c
带有不可拷贝、不可移动对象的Playground

问题对象的一般化版本如下:

class Object {
public:
  explicit Object(std::size_t initial = 1) : value_(initial) {}

  Object(const Object &) = delete;
  Object(Object &&) = delete;
  Object &operator=(const Object &) = delete;
  Object &operator=(Object &&) = delete;

private:
  std::size_t value_;
};

我的尝试:

template <size_t... Is>
auto create_semaphores_array_details(size_t concurrency_per_service,
                                 std::index_sequence<Is...> /*unused*/)
{
    return std::to_array(
        {(Is, Object(concurrency_per_service))...});
};

template <size_t amount_of_services>
auto create_semaphores_array(size_t concurrency_per_service)
{
    return create_semaphores_array_details(
            concurrency_per_service,
            std::make_index_sequence<amount_of_services>());
};

constexpr size_t amount_of_services
    = 27;

std::array<Object, amount_of_services>
    semaphores_per_services
    = create_semaphores_array<amount_of_services>(
        5);

简而言之,失败的原因是:

is_move_constructible失败

第二次尝试,和上面一样,只是把 std::experimental::make_array(...) 换成 std::to_array({...})。简而言之,它仍然失败,原因是:

使用已删除的Object(Object &&)

有什么办法能够构造出这样的对象并且能够改变对象的数量吗?

解决方案

你不能把不可移动的类型作为参数传给函数来构建那种类型。 C++17的拷贝消除对函数参数不起作用,因为参数是具名的左值。

你必须就地构造;可以用工厂来实现。 你可以使用类似下面的做法:

template <std::size_t N, typename F>
auto make_array_from_factory(F f) -> std::array<std::decay_t<decltype(f())>, N>
{
    return [&]<std::size_t... Is>(std::index_sequence<Is...>){
        return std::array<std::decay_t<decltype(f())>, N>{{(static_cast<void>(Is), f())...}};
    }(std::make_index_sequence<N>());
}

演示

然后

make_array_from_factory<42>([&](){ return Object(concurrency_per_service); });
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章