代码之家  ›  专栏  ›  技术社区  ›  Thornsider3

std::array-如何为无法获得默认构造的对象创建固定大小的类成员[重复]

  •  1
  • Thornsider3  · 技术社区  · 1 周前

    我正在为任何类型构建一个容器类 T 需要保留一个列表 T 其长度在编译时已知。我正在努力寻找一种能很好地解决这个问题的数据结构,因为 std::array 当我试图在构造函数的主体中初始化我的对象时会抱怨。至关重要的是,类型 T 不是默认可构造的。

    这里有一个片段,大约对应于我正在寻找的功能

    #include <array>
    #include <cstddef>
    #include <type_traits>
    
    struct not_default_constructible
    {
        not_default_constructible(int){}
    };
    
    static_assert(!std::is_default_constructible_v<not_default_constructible>);
    
    /*
    Does not compile!
    */
    
    template<typename T, long N>
    struct array_of_ndc
    {
        std::array<T,N> arr;
    
        array_of_ndc(T init)
        {
            for(size_t i = 0; i < N; i++)
            {
                arr[i] = init;
            }
        }
    };
    
    int main()
    {
        array_of_ndc<not_default_constructible, 2> ndc(not_default_constructible{2});
    }
    

    这个代码段(不编译!)的问题是编译器希望我初始化 std::数组 在我的建设者的身体之前。

    这是我写的一个解决方案,但感觉我在和编译器斗争(它破坏了我喜欢的一切 std::数组 ,即迭代器),我想看看是否有一个对STL更友好的解决方案。

    template<typename T, long N>
    struct no_construction_arr
    {
        alignas(T) char data[N * sizeof(T)];
    
        template<typename U>
            requires(std::constructible_from<T,U>)
        no_construction_arr(U&& init)
        {
            for(size_t i = 0; i < N; i++)
            {
                new (&data[i * sizeof(T)]) T (init);
            }
        }
    
        T* operator[](size_t index)
        {
            return reinterpret_cast<T*>(&data[index * sizeof(T)]);
        }
    
        ~no_construction_arr()
        {
            for(size_t i = 0; i < N; i++)
            {
                (reinterpret_cast<T*>(&data[i * sizeof(T)]))->~T();
            }
        }
    };
    

    我还要补充一点,我知道我可以用 std::vector 。这是关于试图利用这样一个事实,即我提前知道我将需要的列表的大小,因此进行不必要的动态分配似乎是浪费。

    1 回复  |  直到 1 周前
        1
  •  4
  •   aschepler    1 周前

    若要获取尚未展开参数包的序列或重复,请使用 std::make_index_sequence :

    #include <utility>
    #include <array>
    
    struct not_default_constructible
    {
        not_default_constructible(int){}
    };
    
    template<typename T, unsigned long N>
    struct array_of_ndc
    {
    public:
        std::array<T,N> arr;
    
        explicit array_of_ndc(const T& init)
          : array_of_ndc(init, std::make_index_sequence<N>{})
        {}
    
    private:
        template <std::size_t ...I>
        explicit array_of_ndc(const T& init, std::index_sequence<I...>)
          : arr{ { (static_cast<void>(I), init)... } }
        {}
    };