在 istreambuf_iterator 中使用 C++20 范围
Using C++20 ranges with istreambuf_iterator
我无法编译一个(非常做作的)C++ ranges example:
#include <ranges>
#include <fstream>
#include <vector>
template <typename R>
auto populate(R&& range)
{
return std::vector<char>(range.begin(), range.end());
}
int main(int argc, char* argv[]) {
auto stream = std::ifstream{"/etc/hosts"};
const auto is_odd = [](auto i) { return (i % 2) == 1; };
const auto hosts_data = populate(
std::ranges::subrange{std::istreambuf_iterator<char>{stream},
std::istreambuf_iterator<char>{}} |
std::views::filter(is_odd)
);
return EXIT_SUCCESS;
}
结果:
<source>:19:35: required from here
<source>:9:17: error: no matching function for call to 'std::vector<char>::vector(std::ranges::filter_view<std::ranges::subrange<std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> >, std::ranges::subrange_kind::unsized>, main(int, char**)::<lambda(auto:13)> >::_Iterator, std::ranges::filter_view<std::ranges::subrange<std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> >, std::ranges::subrange_kind::unsized>, main(int, char**)::<lambda(auto:13)> >::_Iterator)'
9 | return std::vector<char>(range.begin(), range.end());
|
从进一步的实验来看,问题似乎是使用 istreambuf_iterator
引起的,但我不知道为什么。有人可以帮忙吗?
这让我很难过。
filter_view::iterator
指定为,从 [range.filter.iterator]:
constexpr iterator& operator++();
constexpr void operator++(int);
constexpr iterator operator++(int) requires forward_range<V>;
值得注意的是,istreambuf_iterator<char>
的 subrange
不是 forward_range
- 它是 input_range
(因为 istreambuf_iterator
只是 input_iterator
).
因此,postfixoperator++
returnsvoid
代替了iterator
。
因此,我们的特定 filter_view::iterator
不 满足 cpp17-iterator
的要求,因为在 [iterator.traits]/2:
中指定
template<class I>
concept cpp17-iterator =
copyable<I> && requires(I i) {
{ *i } -> can-reference;
{ ++i } -> same_as<I&>;
{ *i++ } -> can-reference; // we fail this one
};
您尝试在 vector
中调用的构造函数被指定为来自 [vector.overview]:
template<class InputIterator>
constexpr vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
也就是说,从[sequence.reqmts]/13:
If the constructor
template<class InputIterator>
X(InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());
is called with a type InputIterator
that does not qualify as an input iterator, then the constructor shall not participate in overload resolution.
并且我们的迭代器类型不符合输入迭代器的条件,因为后缀增量的结果不可解引用(另请参见this table)。
至少这只是一个输入迭代器,因此无论如何都不会提高效率,因此您可以根据是否将 populate()
的实现更改为 if constexpr
您实际上从中得到了一个 cpp17 迭代器(基于检查 is_constructible
),否则只是循环/push_back
。
出于某种原因,range-v3 中的 ranges::to
无法在此处编译,但我认为这是编译器问题。
我无法编译一个(非常做作的)C++ ranges example:
#include <ranges>
#include <fstream>
#include <vector>
template <typename R>
auto populate(R&& range)
{
return std::vector<char>(range.begin(), range.end());
}
int main(int argc, char* argv[]) {
auto stream = std::ifstream{"/etc/hosts"};
const auto is_odd = [](auto i) { return (i % 2) == 1; };
const auto hosts_data = populate(
std::ranges::subrange{std::istreambuf_iterator<char>{stream},
std::istreambuf_iterator<char>{}} |
std::views::filter(is_odd)
);
return EXIT_SUCCESS;
}
结果:
<source>:19:35: required from here
<source>:9:17: error: no matching function for call to 'std::vector<char>::vector(std::ranges::filter_view<std::ranges::subrange<std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> >, std::ranges::subrange_kind::unsized>, main(int, char**)::<lambda(auto:13)> >::_Iterator, std::ranges::filter_view<std::ranges::subrange<std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> >, std::ranges::subrange_kind::unsized>, main(int, char**)::<lambda(auto:13)> >::_Iterator)'
9 | return std::vector<char>(range.begin(), range.end());
|
从进一步的实验来看,问题似乎是使用 istreambuf_iterator
引起的,但我不知道为什么。有人可以帮忙吗?
这让我很难过。
filter_view::iterator
指定为,从 [range.filter.iterator]:
constexpr iterator& operator++();
constexpr void operator++(int);
constexpr iterator operator++(int) requires forward_range<V>;
值得注意的是,istreambuf_iterator<char>
的 subrange
不是 forward_range
- 它是 input_range
(因为 istreambuf_iterator
只是 input_iterator
).
因此,postfixoperator++
returnsvoid
代替了iterator
。
因此,我们的特定 filter_view::iterator
不 满足 cpp17-iterator
的要求,因为在 [iterator.traits]/2:
template<class I>
concept cpp17-iterator =
copyable<I> && requires(I i) {
{ *i } -> can-reference;
{ ++i } -> same_as<I&>;
{ *i++ } -> can-reference; // we fail this one
};
您尝试在 vector
中调用的构造函数被指定为来自 [vector.overview]:
template<class InputIterator>
constexpr vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
也就是说,从[sequence.reqmts]/13:
If the constructor
template<class InputIterator> X(InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type());
is called with a type
InputIterator
that does not qualify as an input iterator, then the constructor shall not participate in overload resolution.
并且我们的迭代器类型不符合输入迭代器的条件,因为后缀增量的结果不可解引用(另请参见this table)。
至少这只是一个输入迭代器,因此无论如何都不会提高效率,因此您可以根据是否将 populate()
的实现更改为 if constexpr
您实际上从中得到了一个 cpp17 迭代器(基于检查 is_constructible
),否则只是循环/push_back
。
出于某种原因,range-v3 中的 ranges::to
无法在此处编译,但我认为这是编译器问题。