简体   繁体   English

如何静态断言 std::array 类成员在 c++11 中排序?

[英]How to can a std::array class member be statically asserted to be sorted in c++11?

How can it be asserted, during compile time, that a std::array<uint8_t, 3> class member is sorted?在编译期间,如何断言std::array<uint8_t, 3>类成员已排序? This would allow it to be made const , use a static_assert() and not have to call std::sort() in the constructor.这将允许它成为const ,使用static_assert()而不必在构造函数中调用std::sort()

In c++20 std::is_sorted() has become a constexpr, but is not available for prior versions.在 c++20 中std::is_sorted()已成为 constexpr,但不适用于以前的版本。

Here's a proof of concept implementation that can be called directly on a std::array ;这是一个可以直接在std::array上调用的概念实现证明; making this more general (for other constexpr container types) is left as an exercise to the reader:使这更通用(对于其他 constexpr 容器类型)留给读者作为练习:

template <typename T, std::size_t N>
constexpr bool is_sorted(std::array<T, N> const& arr, std::size_t from) {
    return N - from == 0 or (arr[from - 1] <= arr[from] and is_sorted(arr, from + 1));
}

template <typename T, std::size_t N>
constexpr bool is_sorted(std::array<T, N> const& arr) {
    return N == 0 or is_sorted(arr, 1);
}

Disclaimer: This requires C++14, since, as I have mentioned in the comments, you probably cannot implement a constexpr version of is_sorted for std::array prior to C++14 due to some operations on std::array not being constexpr 1 in C++11 ( operator[] / std::get<> ).免责声明:这需要 C++14,因为正如我在评论中提到的,由于std::array上的某些操作没有被执行,您可能无法在 C++14 之前为std::array实现is_sortedconstexpr版本C++11 中的constexpr 1 ( operator[] / std::get<> )。

With a C++14 implementation, you can use a standard for -loop in your constexpr function and use this very simple implementation:使用 C++14 实现,您可以在constexpr函数中使用标准for -loop 并使用这个非常简单的实现:

template<typename T, std::size_t N>
constexpr bool is_sorted(std::array<T, N> const &arr) {
    for (std::size_t i = 0; i < arr.size() - 1; ++i) {
        if (arr[i] > arr[i + 1]) {
            return false;
        }
    }
    return true;
}

Note that implementing is_sorted for other containers based on iterators ( array , span , string_view ) probably requires C++20 since there are no such things as ConstexprIterator prior to C++20.请注意,为基于迭代器( arrayspanstring_view )的其他容器实现is_sorted可能需要 C++20,因为在 C++20 之前没有ConstexprIterator这样的东西。

1 It looks like gcc and clang provide these members as constexpr even with -std=c++11 , so if this is okay for you, you can use one of the two other answers. 1即使使用-std=c++11 ,看起来 gcc 和 clang 也将这些成员作为constexpr提供,所以如果这对您来说没问题,您可以使用其他两个答案之一。

Not as nice as the other solution, but I wanted to show that this is possible (even if annoyingly so) in C++11 (building on @KonradRudolph's solution)不像其他解决方案那么好,但我想表明在 C++11 中这是可能的(即使很烦人)(建立在@KonradRudolph 的解决方案上)

Edit: This is also just C++14, since std::get is only constexpr since then.编辑:这也只是 C++14,因为从那时起std::get只是constexpr The page on it on cppref has been confusing but has since then be fixed. cppref 上的页面一直令人困惑,但此后已修复。

#include <array>
#include <type_traits>

template<typename T, std::size_t N, std::size_t from>
constexpr typename std::enable_if<from == N, bool>::type
    is_sorted_impl(std::array<T, N> const &arr)
{
    return true;
}

template<typename T, std::size_t N, std::size_t from,
         class = typename std::enable_if<from<N>::type> 
constexpr bool is_sorted_impl(std::array<T, N> const &arr)
{
    return N - from == 0 or (std::get<from - 1>(arr) <= std::get<from>(arr) and
                             is_sorted_impl<T, N, from + 1>(arr));
}

template<typename T, std::size_t N>
constexpr bool is_sorted(std::array<T, N> const &arr)
{
    return N == 0 or is_sorted_impl<T, N, 1>(arr);
}

int main()
{
    constexpr std::array<int, 5> arr{1, 2, 3, 4, 5};
    static_assert(is_sorted(arr), "test");
}

We use std::get which was constexpr since it was introduced in C++14.我们使用std::get ,它是constexpr因为它是在 C++14 中引入的。 To get around instantiating the std::get<N> (which gives obviously a compile time error) we specialize the function template for the case that from == N (which we need to do with enable_if since partial function template specializations are not allowed).为了避免实例化std::get<N> (这显然会导致编译时错误),我们专门针对from == N的情况使用函数模板(我们需要使用enable_if因为不允许部分函数模板特化)。 Not nice, but possible.不太好,但可能。

On another note: @KonradRudolph's solution compiles under gcc and clang also with -std=c++11 -pedantic , altough it should not due to the operator[] not being constexpr is this a bug?另请注意:@KonradRudolph 的解决方案在 gcc 和 clang 下编译,也使用-std=c++11 -pedantic ,虽然它不应该是由于operator[]不是constexpr这是一个错误?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM