Uma vez perguntei se std::ranges::views::enumerate
usa o tipo errado ( long
) para indexação no GCC, mas aparentemente não é o caso , porque
std::views::enumerate
é especificado para ser usadorange_difference_t<Base>
como seu valor de índice.
No entanto, a partir do rascunho
O tipo
size_t
é um tipo inteiro sem sinal definido pela implementação que é grande o suficiente para conter o tamanho em bytes de qualquer objeto ( [expr.sizeof] ).
Portanto, pode-se pensar em uma matriz tão longa que os elementos finais de algum índice em diante não se encaixam no tipo usado para enumerate
indexação, embora ainda se encaixem std::size_t
por definição, desde que em uma determinada máquina, o seguinte seja válido
static_assert(std::numeric_limits<std::size_t>::max() > std::numeric_limits<long>::max());
Por exemplo, tal matriz seria esta:
std::vector<int> v(std::numeric_limits<std::size_t>::max());
para o qual eu gostaria de saber como k
evolui o seguinte:
auto w = v | std::ranges::views::enumerate;
for (auto [k, _] : w) {
std::cout << k << std::endl;
}
Infelizmente, std::vector
não parece permitir esse tamanho de forma alguma, lançando exceções, enquanto um std::array
com esse mesmo tamanho nem é compilável (exemplo completo aqui ), mas presumo que nenhum comportamento seja obrigatório pelo padrão. Ou é?
Não, é possível que
enumerate
não seja possível enumerar todos os elementos de um array.Mas isso não é nada incomum. É um problema geral que sempre existiu em C e C++.
Por exemplo, se
std::size_t
estd::ptrdiff_t
têm a mesma largura de bits e a implementação realmente permite que os objetos tenham o tamanhostd::numeric_limits<std::size_t>::max()
, entãoserá válido, mas
std::numeric_limits<std::ptrdiff_t>::max()
será menor que o índice máximo do array.range_difference_t
pois o array também éstd::ptrdiff_t
e, portanto,enumerate
acabará transbordando, causando um comportamento indefinido.No entanto, o mesmo problema exato ocorre com qualquer forma de diferenças de ponteiro no array, não apenas
enumerate
. Por exemplo,&arr[std::numeric_limits<std::size_t>::max()-1] - &arr[0]
também tem tipostd::ptrdiff_t
e então tem comportamento indefinido porque o valor não é representável.Então, na prática, a implementação não pode permitir matrizes maiores que o valor máximo de
std::ptrdiff_t
(em vez destd::size_t
) para evitar quebrar completamente a biblioteca padrão e muito código do usuário.O mesmo se aplica ao uso de
size_type
edifference_type
em intervalos/contêineres. Na prática, o tamanho máximo permitido deve ser limitado ao máximo dedifference_type
(em vez desize_type
) para evitar que esses casos extremos de UB sejam possíveis. Não há garantia de que o tamanho de um contêiner possa atingir o valor máximo desize_type
. Os contêineres geralmente têm umamax_size
função de membro para informar o tamanho máximo real.Tudo isso é o motivo pelo qual uma opinião comum é que
size_t
/size_type
foi um erro e que tudo deveria ter sido definido comptrdiff_t
/difference_type
como base. Acho que essa opinião também é o motivo pelo qual a escolha de usardifference_type
inenumerate
(e outras visões) foi feita.