Eu estava experimentando com std::iterator_traits
and std::views::iota
. E de repente descobri que std::iterator_traits
return unexpected type para uma categoria de iterador.
libc++
:
#include <ranges>
int main() {
auto view = std::views::iota(0ULL, 10000000000ULL);
static_assert(
std::is_same_v<
std::iterator_traits<decltype(view.begin())>::iterator_category
, std::input_iterator_tag>
);
}
libstdc++
:
#include <ranges>
int main() {
auto view = std::views::iota(0ULL, 10000000000ULL);
static_assert(
std::is_same_v<
std::iterator_traits<decltype(view.begin())>::iterator_category
, std::output_iterator_tag>
);
}
Qual a razão para isso? Por que a categoria de características difere de std::random_access_tag
?
O tipo de referência de
iota_view<long long unsigned, long long unsigned>::iterator
é prvalue, então ele só pode ser Cpp17InputIterator no máximo.Em libstdc++, seu tipo de diferença é
__int128
, que é um tipo de classe inteira introduzido para resolver estouro de inteiros . Como Cpp17InputIterator exige que o tipo de diferença do iterador seja apenas do tipo inteiro, ele não satisfaz Cpp17InputIterator , o que o torna apenas Cpp17Iterator . Issoiterator_traits::iterator_category
ocorreráoutput_iterator_tag
porque os iteradores de saída do C++17 não exigem que o tipo de diferença exista.libc++ não implementa nenhum tipo de classe inteira, então seu tipo de diferença é apenas simple
long long
, que é um Cpp17InputIterator .Além do que a outra resposta diz, gostaria de salientar que agora existem dois sistemas de classificação de iteradores paralelos.
Você está olhando para a categoria de iteradores do estilo antigo, mas ela não faz muito sentido para os novos iteradores de intervalo. Você deveria estar olhando para a nova categoria. O seguinte passa em todos os compiladores que testei:
std::iterator_traits
é somente para escrita no novo modelo de iterador. Você pode especializá-lo para seus iteradores para substituir algumas de suas propriedades, e os novos conceitos respeitarão isso, mas você não pode ler a partir dele (porque os conceitos são mágicos e só o representam se for especializado, e você não pode verificar manualmente se é especializado ou não, e ler a versão não especializada é inútil no novo modelo).Existem alguns novos iteradores que não são considerados iteradores de acordo com a classificação antiga e, para eles,
std::iterator_traits
estarão vazios: https://gcc.godbolt.org/z/razETYKq3