[英]Using std::ranges algorithms with custom containers and iterators
I have the following simplified code representing a range of integers that I want to use with various std algorithms.我有以下简化代码,表示我想与各种 std 算法一起使用的整数范围。 I am trying to update my code to use C++20's ranges versions of the algorithms so I can delete all of the
begin()
and end()
calls.我正在尝试更新我的代码以使用算法的 C++20 范围版本,以便我可以删除所有
begin()
和end()
调用。 In the below code, std::any_of
works with my container and iterator, but std::ranges::any_of
does not.在下面的代码中,
std::any_of
与我的容器和迭代器一起使用,但std::ranges::any_of
不使用。
#include <iostream>
#include <algorithm>
class Number_Iterator {
public:
using iterator_category = std::input_iterator_tag;
using value_type = int;
using difference_type = int;
using pointer = int*;
using reference = int&;
Number_Iterator(int start) noexcept : value(start) {}
Number_Iterator& operator++() noexcept { ++value; return *this; }
bool operator==(const Number_Iterator& other) const noexcept = default;
int operator*() const noexcept { return value; }
private:
int value;
};
class Numbers {
public:
Numbers(int begin, int end) noexcept : begin_value(begin), end_value(end) {}
Number_Iterator begin() const noexcept { return {begin_value}; }
Number_Iterator end() const noexcept { return {end_value}; }
private:
int begin_value;
int end_value;
};
int main() {
const auto set = Numbers(1, 10);
const auto multiple_of_three = [](const auto n) { return n % 3 == 0; };
// Compiles and runs correctly
if(std::any_of(set.begin(), set.end(), multiple_of_three)) {
std::cout << "Contains multiple of three.\n";
}
// Does not compile
if(std::ranges::any_of(set, multiple_of_three)) {
std::cout << "Contains multiple of three.\n";
}
return 0;
}
When I try to compile the above code, I get the following error messages from Visual Studio 2019 (16.11.15) with the flag /std:c++20
:当我尝试编译上述代码时,我从 Visual Studio 2019 (16.11.15) 收到以下带有
/std:c++20
标志的错误消息:
Source.cpp(42,21): error C2672: 'operator __surrogate_func': no matching overloaded function found
Source.cpp(42,7): error C7602: 'std::ranges::_Any_of_fn::operator ()': the associated constraints are not satisfied
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\algorithm(1191): message : see declaration of 'std::ranges::_Any_of_fn::operator ()'
I have tried looking at the std::ranges::_Any_of_fn::operator()
declaration, but I find myself more confused by that.我曾尝试查看
std::ranges::_Any_of_fn::operator()
声明,但我发现自己对此更加困惑。
What am I missing to get the std::ranges
algorithms to work with my container?为了让
std::ranges
算法与我的容器一起工作,我缺少什么?
For the curious, what I'm actually iterating over are squares on a chess board, but those are represented by integers, so the difference from the above code isn't so great.出于好奇,我实际上迭代的是棋盘上的方格,但这些方格是用整数表示的,因此与上述代码的区别不是很大。
Apparently, the std::ranges
algorithms require two more methods in the iterator: a default constructor and a post-increment operator (return value optional).显然,
std::ranges
算法在迭代器中需要另外两个方法:默认构造函数和后增量运算符(返回值可选)。 Adding these methods allows the code to compile and run correctly:添加这些方法可以使代码正确编译和运行:
Number_Iterator() noexcept : value(-1) {}
void operator++(int) noexcept { ++value; }
To use your range with any_of
it must satisfy the input_range
concept:要将您的范围与
any_of
一起使用,它必须满足input_range
概念:
template< class T >
concept input_range =
ranges::range<T> && std::input_iterator<ranges::iterator_t<T>>;
Then via the input_iterator
concept:然后通过
input_iterator
概念:
template<class I>
concept input_iterator =
std::input_or_output_iterator<I> &&
std::indirectly_readable<I> &&
requires { typename /*ITER_CONCEPT*/<I>; } &&
std::derived_from</*ITER_CONCEPT*/<I>, std::input_iterator_tag>;
and via the input_or_output_iterator
concept并通过
input_or_output_iterator
概念
template <class I>
concept input_or_output_iterator =
requires(I i) {
{ *i } -> /*can-reference*/;
} &&
std::weakly_incrementable<I>;
you land in the weakly_incrementable
concept:你进入了
weakly_incrementable
概念:
template<class I>
concept weakly_incrementable =
std::movable<I> &&
requires(I i) {
typename std::iter_difference_t<I>;
requires /*is-signed-integer-like*/<std::iter_difference_t<I>>;
{ ++i } -> std::same_as<I&>; // pre-increment
i++; // post-increment
};
in which you see that the iterator must have both the pre-increment and post-increment versions of operator++
.您可以在其中看到迭代器必须同时具有
operator++
的前增量和后增量版本。
The iterator must also be default constructible because std::ranges::end
creates a sentinel:迭代器也必须是默认可构造的,因为
std::ranges::end
创建了一个标记:
template< class T >
requires /* ... */
constexpr std::sentinel_for<ranges::iterator_t<T>> auto end( T&& t );
And sentinel_for
还有
sentinel_for
template<class S, class I>
concept sentinel_for =
std::semiregular<S> &&
std::input_or_output_iterator<I> &&
__WeaklyEqualityComparableWith<S, I>;
requires it to satisfy semiregular
:要求它满足
semiregular
:
template <class T>
concept semiregular = std::copyable<T> && std::default_initializable<T>;
But without being default constructible, this substitution will fail:但如果不是默认可构造的,这种替换将失败:
template < class T >
concept default_initializable = std::constructible_from<T> && requires { T{}; } && ...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.