我有一个定义和初始化的数据结构,类似于以下内容:
#include <vector>
#include <array>
struct SomeStruct {
std::vector<int> vec;
};
int main() {
std::array<SomeStruct, 2> arr {
SomeStruct {
.vec = {
1, 2
}
},
SomeStruct {
.vec = {
3, 4, 5
}
}
};
}
这可以正确编译,但是由于整个结构在编译时就已知道,因此我尝试将其设为constexpr
。
在上一个示例中将arr
简单地声明为constexpr
会导致错误:
main.cpp: In function ‘int main()’:
main.cpp:20:5: error: the type ‘const std::array’ of constexpr variable ‘arr’ is not literal
};
^
In file included from main.cpp:2:0:
/usr/include/c++/7/array:94:12: note: ‘std::array’ is not literal because:
struct array
^~~~~
/usr/include/c++/7/array:94:12: note: ‘std::array’ has a non-trivial destructor
我猜这是因为std::vector
没有constexpr
构造函数/析构函数。
然后我尝试在包含struct的模板上使用std::array
:
#include <array>
template <int N>
struct SomeStruct {
std::array<int, N> vec;
};
int main() {
constexpr std::array<SomeStruct, 2> arr {
SomeStruct<2> {
.vec = {
1, 2
}
},
SomeStruct<3> {
.vec = {
3, 4, 5
}
}
};
}
这也会导致错误:
main.cpp: In function ‘int main()’:
main.cpp:10:39: error: type/value mismatch at argument 1 in template parameter list for ‘template struct std::array’
constexpr std::array<SomeStruct, 2> arr {
^
main.cpp:10:39: note: expected a type, got ‘SomeStruct’
main.cpp:10:41: error: scalar object ‘arr’ requires one element in initializer
constexpr std::array<SomeStruct, 2> arr {
^~~
但是我不能给SomeStruct模板参数,因为大小可能不同。
定义这样的constexpr
数据结构的最佳方法是什么?
答案 0 :(得分:3)
就像说here
由于
std::array<T, N>
是一个聚合,并且仅当基础类型T
具有constexpr构造函数时(可以与您提供的每个初始化程序一起使用时),才能将其初始化为constexpr。
由于std::vector
没有constexpr构造函数(yet),因此将无法正常工作。
因此,对于C ++ 20之前的版本,这不适用于动态大小的STL容器。没有解决方案或快速修复。不要抱有希望。
另一种方法是设计自己的constexpr固定最大大小Vector
类。例如
template <typename T, std::size_t N>
class Vector {
private:
T values[N]{};
public:
std::size_t size{ 0 };
constexpr bool empty() const noexcept { return size == 0; }
constexpr void clear() noexcept { size = 0; }
constexpr T* begin() noexcept { return &values[0]; }
constexpr T* end() noexcept { return &values[size]; }
constexpr T const* cbegin() const noexcept { return &values[0]; }
constexpr T const* cend() const noexcept { return &values[size]; }
constexpr T& back() noexcept { return values[size - 1]; }
constexpr T operator[] (int const loc) const noexcept { return values[loc]; }
constexpr T& operator[] (int const loc) noexcept { return values[loc]; }
constexpr void push_back(T const& value) noexcept { values[size++] = value; }
constexpr void resize(int const newSize) noexcept {
auto const diff = newSize - size;
if (diff > 0) memset(end(), 0, diff * sizeof(T));
size = newSize;
}
};
这是我有时使用的一个...您需要添加一个initializer_list
构造函数。
编辑:快速测试...这似乎可以编译。
#include <array>
template <typename T, std::size_t N>
class Vector {
private:
T values[N]{};
public:
std::size_t size{ 0 };
constexpr Vector(std::initializer_list<T> il) noexcept
: size(std::distance(std::cbegin(il), std::cend(il)))
{
std::size_t i = 0;
for(auto it = std::cbegin(il); it != std::cend(il); ++it) {
values[i++]=*it;
}
}
};
struct SomeStruct {
Vector<int,5> vec;
};
int main() {
[[maybe_unused]]constexpr std::array<SomeStruct, 2> arr {
SomeStruct {
.vec = {
1, 2
}
},
SomeStruct {
.vec = {
3, 4, 5
}
}
};
}
答案 1 :(得分:2)
如果分别存储行,则可以有一个跨度数组。您必须使行保持活动至少与父数组一样长。在此示例中,通过将它们作为相同作用域中的变量来实现:
struct SomeStruct {
std::span<int> vec;
};
std::array arr1 {1, 2};
std::array arr2 {3, 4, 5};
constexpr std::array arr {
SomeStruct { .vec = arr1 },
SomeStruct { .vec = arr2 },
};
或者,具有更多constexpr的非可变版本:
struct SomeStruct {
std::span<const int> vec;
};
constexpr std::array arr1 {1, 2};
constexpr std::array arr2 {3, 4, 5};
constexpr std::array arr {
SomeStruct { .vec = arr1 },
SomeStruct { .vec = arr2 },
};