我正在为任何类型
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;
}
}
};
此代码片段的问题(无法编译!)是编译器希望我在构造函数主体之前初始化我的
std::array
。
这是我写的一个解决方案,但感觉就像我在与编译器战斗(它破坏了我喜欢的一切
std::array
,即迭代器),我想看看是否有更多的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
做到这一点。这是关于尝试利用这样一个事实:我提前知道我需要的列表的大小,因此进行不需要的动态分配似乎很浪费。
要获取尚未有要扩展的参数包的序列或重复,请使用
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)... } }
{}
};