Quero uma visão dos caracteres de um fluxo de entrada:
auto input = std::stringstream{"abcd"};
using Iter = std::istreambuf_iterator<char>;
auto s = std::ranges::subrange{Iter{input}, Iter{}};
Até aqui, tudo bem. Agora, eu transformo essa visualização (usando uma transformação de identidade para simplificar):
auto t = s | std::views::transform(std::identity{});
Embora esta visão transformada tenha uma validade value_type
(ou seja, esta afirmação passa):
using T = decltype(t);
static_assert(std::is_same_v<char, std::ranges::range_value_t<T>>);
o tipo de iterador dele não tem um:
static_assert(std::is_same_v<char, std::iterator_traits<std::ranges::iterator_t<T>>::value_type>);
Isso falha com
view.cc: In function 'int main()':
view.cc:27:90: error: 'value_type' is not a member of 'std::iterator_traits<std::ranges::transform_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>, std::identity>::_Iterator<false> >'
27 | static_assert(std::is_same_v<char, std::iterator_traits<std::ranges::iterator_t<T>>::value_type>);
| ^~~~~~~~~~
view.cc:27:100: error: template argument 2 is invalid
27 | static_assert(std::is_same_v<char, std::iterator_traits<std::ranges::iterator_t<T>>::value_type>);
|
A razão pela qual isso é importante para mim é que quero usar as características do iterador em um adaptador de visualização posterior.
A investigação sugere que o iterador da visualização de transformação não possui seu iterator_category
membro. O código funciona bem quando passo um intervalo mais capaz, como std::string
para a transformação, mas falha com esse intervalo não direto.
Código completo (também no Compiler Explorer ):
#include <functional>
#include <iterator>
#include <ranges>
#include <sstream>
#include <string>
#include <type_traits>
int main()
{
#ifdef PASS
auto input = std::string{"abcd"};
std::ranges::forward_range auto s = std::ranges::subrange(input.begin(), input.end());
#else
auto input = std::stringstream{"abcd"};
using Iter = std::istreambuf_iterator<char>;
std::ranges::input_range auto s = std::ranges::subrange{Iter{input}, Iter{}};
#endif
using S = decltype(s);
static_assert(std::is_same_v<char, std::ranges::range_value_t<S>>);
static_assert(std::is_same_v<char, std::iterator_traits<std::ranges::iterator_t<S>>::value_type>);
auto t = s | std::views::transform(std::identity{});
using T = decltype(t);
static_assert(std::is_same_v<char, std::ranges::range_value_t<T>>);
static_assert(std::is_same_v<char, std::ranges::iterator_t<T>::value_type>);
static_assert(std::is_base_of_v<std::input_iterator_tag, std::ranges::iterator_t<T>::iterator_category>);
static_assert(std::is_same_v<char, std::iterator_traits<std::ranges::iterator_t<T>>::value_type>);
}