我想创建一个constexpr容器,如std::数组,也排序,所有元素都是唯一的。我想要实现的是在编译时检查构造函数中给定的数据是否排序和唯一。我相信std::set接口更接近我想要实现的,但它不是constexpr(还没有?)我计划创建一个包装器并在内部使用std::数组,同时对外公开std::set接口。
当前的实现是这样的
struct ConstexprSet
{
constexpr ConstexprSet(const std::array<DataType, Size>& data) : mData(data)
{
if constexpr (!std::is_sorted(std::cbegin(mData), std::cend(mData)))
throw std::runtime_error("Data not sorted");
if constexpr (std::adjacent_find(std::cbegin(mData), std::cend(mData)) != std::cend(mData))
throw std::runtime_error("Data not unique");
}
[[nodiscard]] constexpr auto GetData() const noexcept { return mData; }
private:
std::array<DataType, Size> mData;
};
我得到的错误是"this"不是一个常量表达式。如果我用data参数改变mData,我得到数据不是常量表达式。那么什么是常数表达式呢?如果我将整个数组作为NTTP传递,这能工作吗?
期望的用例是这样的
constexpr ConstexprSet features{"A"sv, "B"sv, "C"sv, "D"sv, "E"sv, "F"sv};
,其中模板参数将从输入参数中推断出来,就像在std::数组中一样。
下面的两个例子不应该编译成功,他们应该给出全面的消息
constexpr ConstexprSet features{"A"sv, "D"sv, "C"sv, "B"sv, "E"sv, "F"sv}; // Data not sorted
constexpr ConstexprSet features{"A"sv, "B"sv, "B"sv, "D"sv, "E"sv, "F"sv}; // Data not unique
另一个失败的实验是创建一个带有初始化列表的构造函数,并将其直接传递给内部数组,但这也不起作用…
如果有任何关于如何克服这个问题的想法,或者任何我可以遵循的方法来实现这个容器的预期行为,我将非常欢迎
我用于实验的当前草稿可以在这里找到https://godbolt.org/z/1468cEjhW
struct ConstexprSet { std::array<DataType, Size> mData;
你不能这样做——在类级别,DataType
和Size
甚至不是声明的标识符。
让我们声明它们(T
代表DataType
,n
代表Size
):
template<typename T, auto n> class Set {
std::array<T, n> mData;
// TODO
然后你需要一个构造函数我想要实现的是在编译时检查构造函数中给定的数据是否排序且唯一
consteval
(must在编译时运行),而不是constexpr
(运行时/编译时"多态"):
public:
consteval Set(auto... ts): mData{std::move(ts)...} {
if (n == 0) return; // can't think of a ready STL algorithm
for (auto prev = mData.begin(), cur = prev + 1; cur != mData.end(); ++prev, ++cur)
if (*prev >= *cur)
throw std::logic_error{"not sorted / not unique"};
}
};
方便的演绎指南:
Set(auto t, auto... ts) -> Set<decltype(t), sizeof...(ts) + 1>;
测试:
int main() {
constexpr Set set1{"A"sv, "B"sv, "D"sv}; // ok
constexpr Set set2{"A"sv, "D"sv, "B"sv}; // error
constexpr Set set3{"A"sv, "D"sv, "D"sv}; // error
}
应该给出全面的信息
source>:24:16: error: constexpr variable 'set2' must be initialized by a constant expression
constexpr Set set2{"A"sv, "D"sv, "B"sv}; // error
^~~~~~~~~~~~~~~~~~~~~~~~~
<source>:17:5: note: subexpression not valid in a constant expression
throw std::logic_error{"not sorted / not unique"};
source>:25:16: error: constexpr variable 'set3' must be initialized by a constant expression
constexpr Set set3{"A"sv, "D"sv, "D"sv}; // error
^~~~~~~~~~~~~~~~~~~~~~~~~
<source>:17:5: note: subexpression not valid in a constant expression
throw std::logic_error{"not sorted / not unique"};