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 级别,DataTypeSize 甚至都没有声明标识符。

让我们声明它们(T 代表 DataTypen 代表 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"};