В еще один вопрос появилась тема std::numeric_limits<int>::is_modulo. Но чем больше я думаю об этом, тем больше кажется, что что-то не так с spec или с GCC или обоими.
Позвольте мне начать с кода:
#include <limits>
#include <iostream>
bool test(int x)
{
return x+1 > x;
}
int main(int argc, char *argv[])
{
int big = std::numeric_limits<int>::max();
std::cout << std::numeric_limits<int>::is_modulo << " ";
std::cout << big+1 << " ";
std::cout << test(big) << "\n";
}
Когда я компилирую это с помощью g++ -O3 -std=c++11 (x86_64 GCC 4.7.2), он производит следующий вывод:
1 -2147483648 1
То есть, is_modulo истинно, один плюс INT_MAX отрицателен, а один плюс INT_MAX больше, чем INT_MAX.
Если вы такой человек, у которого есть реальный шанс ответить на этот вопрос, вы уже знаете, что здесь произошло. В спецификации С++ указано, что переполнение целых чисел Undefined Behavior; компилятор допускает, что вы этого не делаете; поэтому аргумент x+1 не может быть INT_MAX; поэтому компилятор может (и будет) компилировать функцию test для возврата true безоговорочно. Пока что так хорошо.
Однако С++ 11 spec также говорит (18.3.2.4 абзацы 60-61):
static constexpr is_modulo;Истинно, если тип по модулю .222 Тип по модулю, если для любой операции с участием
+,-или*по значениям этого типа, результат которых выходят за пределы диапазона[min(),max()], возвращаемое значение отличается от истинного значения целым числом, кратнымmax() - min() + 1.На большинстве машин это
falseдля плавающих типов,trueдля целые числа без знака иtrueдля целых чисел со знаком.
Обратите внимание, что в параграфе (5) раздела 5 все еще читается: "Если во время оценки выражения результат не определен математически или нет в диапазоне представляемых значений для его типа, поведение undefined". Не упоминается is_modulo == true создание исключения.
Таким образом, мне кажется, что стандарт логически противоречив, потому что одновременное переполнение целых чисел не может быть определено и undefined. Или, по крайней мере, GCC является несоответствующим, потому что он имеет is_modulo как true, хотя подписанная арифметика, безусловно, не оборачивается.
Является ли стандартная ошибка? Не соответствует ли GCC? Я что-то пропустил?