Ответ 1
Возможно ли даже, что результат
ijне должен находиться в диапазоне представимых значенийptrdiff_t?
Да, но это маловероятно.
Фактически, [support.types.layout]/2 не говорит много, кроме правильных правил вычитания указателей, а ptrdiff_t определены в [expr.add]. Итак, посмотрим на этот раздел.
[expr.add]/5Когда два указателя на элементы одного и того же объекта массива вычитаются, тип результата представляет собой определенный интегральным типом, определенный реализацией; этот тип должен быть того же типа, который определяется как
std::ptrdiff_tв заголовке<cstddef>.
Прежде всего, обратите внимание, что случай, когда i и j - индексы индексов разных массивов, не рассматривается. Это позволяет рассматривать ij как PQ, где P является указателем на элемент массива в индексе i а Q является указателем на элемент того же массива в индексе j. В деле вычитание двух указателей на элементы разных массивов - это неопределенное поведение:
[expr.add]/5Если выражения
PиQуказывают соответственно на элементыx[i]иx[j]одного и того же объекта массиваx, выражениеP - Qимеет значениеi−j; в противном случае поведение не определено.
В качестве вывода, с обозначением, определенным ранее, ij и PQ определены равными значениям, причем последний имеет тип std::ptrdiff_t. Но ничего не говорится о возможности того, чтобы этот тип имел такую ценность. Однако на этот вопрос можно ответить с помощью std::numeric_limits; особенно, можно определить, является ли массив some_array слишком большим для std::ptrdiff_t чтобы удерживать все разности индексов:
static_assert(std::numeric_limits<std::ptrdiff_t>::max() > sizeof(some_array)/sizeof(some_array[0]),
"some_array is too big, subtracting its first and one-past-the-end element indexes "
"or pointers would lead to undefined behavior as per [expr.add]/5."
);
Теперь, на обычной цели, это обычно не происходит как sizeof(std::ptrdiff_t) == sizeof(void*); что означает, что массив должен быть глупо большим для ptrdiff_t для переполнения. Но нет никакой гарантии.