В еще один вопрос появилась тема 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? Я что-то пропустил?