Это меня огорчает.
filter_view::iterator
определяется как [range.filter.iterator] :
constexpr iterator& operator++();
constexpr void operator++(int);
constexpr iterator operator++(int) requires forward_range<V>;
Примечательно, что subrange
из istreambuf_iterator<char>
не forward_range
- это input_range
(потому что istreambuf_iterator
- это только input_iterator
).
Таким образом, постфикс operator++
возвращает void
вместо 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
, указан как from [vector.overview] :
template<class InputIterator>
constexpr vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
Это означает, что из [sequence.reqmts] / 13 :
Если конструктор
template<class InputIterator>
X(InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());
вызывается с типом InputIterator
, не квалифицируется как итератор ввода, тогда конструктор не должен участвовать в разрешении перегрузки.
И наш тип итератора не квалифицируется как итератор ввода, потому что результат постфиксного приращения не разыменовывается (см. также эту таблицу ).
По крайней мере, это всего лишь итератор ввода, так что никакого выигрыша в эффективности в любом случае не будет, поэтому вы можете просто изменить свою реализацию populate()
на if constexpr
в зависимости от того, действительно ли вы получаете cpp17- итератор из него (на основе проверки is_constructible
) и просто loop / push_back
в противном случае.
По какой-то причине ranges::to
from range-v3 здесь не компилируется, но я думаю, что это проблема компилятора .