如何在C++11中静态断言一个std::array类成员已排序?

huangapple go评论81阅读模式
英文:

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

问题

如何在编译时断言 std::array<uint8_t, 3> 类成员已排序?这将允许将其设为 const,使用 static_assert(),而无需在构造函数中调用 std::sort()

在 C++20 中,std::is_sorted() 已经成为了一个 constexpr,但在之前的版本中不可用。

英文:

How can it be asserted, during compile time, that a std::array&lt;uint8_t, 3&gt; class member is sorted? This would allow it to be made const, use a static_assert() and not have to call std::sort() in the constructor.

In c++20 std::is_sorted() has become a constexpr, but is not available for prior versions.

答案1

得分: 3

以下是您要翻译的内容:

这是一个概念验证实现,可以直接在std::array上调用;将其更一般化(适用于其他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);
}
英文:

Here’s a proof of concept implementation that can be called directly on a std::array; making this more general (for other constexpr container types) is left as an exercise to the reader:

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

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

答案2

得分: 1

Here's the translated content:

免责声明: 这需要使用C++14,因为正如我在评论中提到的,你可能无法在C++11之前为std::array实现constexpr版本的is_sorted,因为C++11中对std::array的某些操作不是constexpr1的(例如operator[] / std::get<>)。

使用C++14的实现,你可以在constexpr函数中使用标准的for循环,并使用这个非常简单的实现:

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;
}

请注意,为其他基于迭代器的容器(例如arrayspanstring_view)实现is_sorted可能需要C++20,因为在C++20之前没有ConstexprIterator这样的东西。

1看起来gcc和clang即使在使用-std=c++11的情况下也会提供这些成员作为constexpr,所以如果这对你来说可以接受,你可以使用另外两个答案中的其中一个。

英文:

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<sup>1</sup> in C++11 (operator[] / std::get&lt;&gt;).

With a C++14 implementation, you can use a standard for-loop in your constexpr function and use this very simple implementation:

template&lt;typename T, std::size_t N&gt;
constexpr bool is_sorted(std::array&lt;T, N&gt; const &amp;arr) {
    for (std::size_t i = 0; i &lt; arr.size() - 1; ++i) {
        if (arr[i] &gt; 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.

<sub><sup>1</sup> 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.</sub>

答案3

得分: 0

Here is the translated code portion:

不如另一种解决方案那么好,但我想展示这在C++11中是可能的(尽管有点烦人)(基于@KonradRudolph的解决方案

编辑:这也仅适用于C++14,因为自那时起`std::get`才是`constexpr`的。 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");
}

感谢您的理解。

英文:

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)

Edit: This is also just C++14, since std::get is only constexpr since then. The page on it on cppref has been confusing but has since then be fixed.

#include &lt;array&gt;
#include &lt;type_traits&gt;

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

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

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

int main()
{
    constexpr std::array&lt;int, 5&gt; arr{1, 2, 3, 4, 5};
    static_assert(is_sorted(arr), &quot;test&quot;);
}

We use std::get which was constexpr since it was introduced in C++14. To get around instantiating the std::get&lt;N&gt; (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). 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?

huangapple
  • 本文由 发表于 2020年1月6日 21:52:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/59613339.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定