来自C ++ Now 2017的Jason Turner和Ben Deane有一个很好的演讲,名为constexpr All the things
,它也给出了constexpr
矢量实现。出于教育目的,我本人也想这个主意。我的constexpr向量是纯粹的,因为将其推回会返回带有添加元素的新向量。
在谈话中,我看到push_back
实现的实现或多或少如下:
constexpr void push_back(T const& e) {
if(size_ >= Size)
throw std::range_error("can't use more than Size");
else {
storage_[size_++] = e;
}
}
他们以价值为要素并加以移动,但是,我认为这不是我的问题的根源。我想知道的是,该函数如何在constexpr上下文中使用?这不是const成员函数,它修改状态。我不认为可以做类似的事情
constexpr cv::vector<int> v1;
v1.push_back(42);
如果这不可能,那么我们如何在constexpr上下文中使用此东西,并使用此向量(即编译时JSON解析)实现任务的目标?
这是我的版本,因此您可以看到我的新引导程序返回版本和谈话中的版本。 (请注意,忽略了性能,完美转发等问题)
#include <cstdint>
#include <array>
#include <type_traits>
namespace cx {
template <typename T, std::size_t Size = 10>
struct vector {
using iterator = typename std::array<T, Size>::iterator;
using const_iterator = typename std::array<T, Size>::const_iterator;
constexpr vector(std::initializer_list<T> const& l) {
for(auto& t : l) {
if(size_++ < Size)
storage_[size_] = std::move(t);
else
break;
}
}
constexpr vector(vector const& o, T const& t) {
storage_ = o.storage_;
size_ = o.size_;
storage_[size_++] = t;
}
constexpr auto begin() const { return storage_.begin(); }
constexpr auto end() const { return storage_.begin() + size_; }
constexpr auto size() const { return size_; }
constexpr void push_back(T const& e) {
if(size_ >= Size)
throw std::range_error("can't use more than Size");
else {
storage_[size_++] = e;
}
}
std::array<T, Size> storage_{};
std::size_t size_{};
};
}
template <typename T>
constexpr auto make_vector(std::initializer_list<T> const& l) {
return cx::vector<int>{l};
}
template <typename T>
constexpr auto push_back(cx::vector<T> const& o, T const& t) {
return cx::vector<int>{o, t};
}
int main() {
constexpr auto v1 = make_vector({1, 2, 3});
static_assert(v1.size() == 3);
constexpr auto v2 = push_back(v1, 4);
static_assert(v2.size() == 4);
static_assert(std::is_same_v<decltype(v1), decltype(v2)>);
// v1.push_back(4); fails on a constexpr context
}
所以,这件事使我意识到关于constexpr可能有一些我不了解的地方。因此,重提问题;这样的constexpr向量如何在constexpr上下文中提供像这样的变异push_back
?似乎它现在不能在constexpr上下文中使用。如果不打算在constexpr上下文中使用push_back
,那么如何将其称为constexpr向量并将其用于编译时JSON解析?
答案 0 :(得分:4)
您对向量的定义是正确的,但是您不能修改constexpr
个对象。它们是健康且真正恒定的。相反,请在constexpr
函数内部进行编译时计算(然后可以将其输出分配给constexpr
对象)。
例如,我们可以编写一个函数range
,该函数产生一个从0
到n
的数字向量。它使用push_back
,我们可以将结果分配给constexpr
中的main
向量。
constexpr vector<int> range(int n) {
vector<int> v{};
for(int i = 0; i < n; i++) {
v.push_back(i);
}
return v;
}
int main() {
constexpr vector<int> v = range(10);
}