Constexpr 排序的唯一容器集作为数组包装器
Constexpr Sorted Unique Container Set as Array wrapper
我想创建一个类似 std::array 的 constexpr 容器,它也被排序并且所有元素都是唯一的。我想要实现的是在编译时检查构造函数中的给定数据是否已排序且唯一。我相信 std::set 接口更接近我想要实现的目标,但它不是 constexpr(还?)。我计划创建一个包装器并在内部使用 std::array,同时在外部公开 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”不是常量表达式。如果我用数据参数更改 mData,我会得到数据不是常量表达式。那么究竟什么是常量表达式呢?
如果我将整个数组作为 NTTP 传递,这会起作用吗?
理想的用例应该是这样的
constexpr ConstexprSet features{"A"sv, "B"sv, "C"sv, "D"sv, "E"sv, "F"sv};
模板参数将从输入参数中推导出来,就像在 std::array 中所做的那样。
下面两个例子应该没有编译成功,应该给出综合信息
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;
你不能这样做 - 在 class 级别,DataType
和 Size
甚至都没有声明标识符。
让我们声明它们(T
代表 DataType
,n
代表 Size
):
template<typename T, auto n> class Set {
std::array<T, n> mData;
// TODO
What I want to achieve is to check at compile time if the given data in the constructor are sorted and unique
然后你需要一个consteval
的构造函数(必须在编译时是运行) , 不是 constexpr
(runtime/compile-time “多态”):
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
}
should give comprehensive messages
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"};
我想创建一个类似 std::array 的 constexpr 容器,它也被排序并且所有元素都是唯一的。我想要实现的是在编译时检查构造函数中的给定数据是否已排序且唯一。我相信 std::set 接口更接近我想要实现的目标,但它不是 constexpr(还?)。我计划创建一个包装器并在内部使用 std::array,同时在外部公开 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”不是常量表达式。如果我用数据参数更改 mData,我会得到数据不是常量表达式。那么究竟什么是常量表达式呢? 如果我将整个数组作为 NTTP 传递,这会起作用吗?
理想的用例应该是这样的
constexpr ConstexprSet features{"A"sv, "B"sv, "C"sv, "D"sv, "E"sv, "F"sv};
模板参数将从输入参数中推导出来,就像在 std::array 中所做的那样。
下面两个例子应该没有编译成功,应该给出综合信息
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;
你不能这样做 - 在 class 级别,DataType
和 Size
甚至都没有声明标识符。
让我们声明它们(T
代表 DataType
,n
代表 Size
):
template<typename T, auto n> class Set {
std::array<T, n> mData;
// TODO
What I want to achieve is to check at compile time if the given data in the constructor are sorted and unique
然后你需要一个consteval
的构造函数(必须在编译时是运行) , 不是 constexpr
(runtime/compile-time “多态”):
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
}
should give comprehensive messages
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"};