Согласно С++ 03, 5.8/2, сдвиг влево определяется следующим образом:
Значение E1 < E2 - E1 (интерпретируется как битовый шаблон), сдвинутые слева позиции E2; освобожденные биты заполняются нулями. Если E1 имеет неподписанный тип, значение результата E1 умножается на величину 2, поднятую до мощности E2, уменьшенную по модулю ULONG_MAX + 1, если E1 имеет тип unsigned long, UINT_MAX + 1 в противном случае.
Меня беспокоит то, что неподписанные типы явно упоминаются, но подписанные типы полностью игнорируются. Сравните это с 5.8/3, который определяет правое смещение:
Значение E1 → E2 - это позиции E1 с правым сдвигом E1. Если E1 имеет неподписанный тип, или если E1 имеет подписанный тип и неотрицательное значение, значение результата является неотъемлемой частью частного E1, деленной на величину 2, поднятую до мощности E2. Если E1 имеет подписанный тип и отрицательное значение, результирующее значение определяется реализацией.
В 5.8/3 указаны как подписанные, так и unsigned, даже подписанные с неотрицательными и подписанными отрицательными значениями, упомянутыми отдельно.
AFAIK, когда что-то явно не определено в стандарте С++, поведение undefined. Я также видел этот вопрос, но он фокусируется на различиях между C и С++ и, похоже, не имеет ответа, на который все согласятся.
Является ли сдвиг слева целочисленным знаком, определенным в С++ 03?