英文:
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<uint8_t, 3>
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 <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);
}
答案2
得分: 1
Here's the translated content:
免责声明: 这需要使用C++14,因为正如我在评论中提到的,你可能无法在C++11之前为std::array
实现constexpr
版本的is_sorted
,因为C++11中对std::array
的某些操作不是constexpr
1的(例如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;
}
请注意,为其他基于迭代器的容器(例如array
、span
、string_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<>
).
With a C++14 implementation, you can use a standard for
-loop in your constexpr
function and use this very simple implementation:
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.
<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 <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. 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). 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?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论