Bool operator ++ и -

Сегодня, написав код Visual С++, я столкнулся с чем-то, что меня удивило. Кажется, С++ поддерживает ++ (increment) для bool, но не - (декремент). Это просто случайное решение, или есть какая-то причина этого?

Это компилируется:

static HMODULE hMod = NULL;
static bool once = false;
if (!once++)
    hMod = LoadLibrary("xxx");

Это не означает:

static HMODULE hMod = NULL;
static bool once = true;
if (once--)
    hMod = LoadLibrary("xxx");

Ответ 1

Он исходит из истории использования целочисленных значений как booleans.

Если x является int, но я использую его как логическое значение в соответствии с if(x)..., то приращение будет означать, что независимо от его значения истинности перед операцией он будет иметь значение истинности true после него (запрет переполнения).

Однако невозможно предсказать результат -- данного знания только значения истинности x, поскольку это может привести к false (если интегральное значение равно 1) или true (если интегральное значение - это что-то еще - в частности, это 0 [false] и 2 или более [true]).

Итак, как работает короткая рука ++, а -- - нет.

++ разрешен для bools для совместимости с этим, но его использование устарело в стандарте.


Это предполагает, что я только использует x как логическое значение, что означает, что переполнение не может произойти, пока я не сделал ++ достаточно часто, чтобы вызвать переполнение на нем. Даже с char как используемым типом и CHAR_BITS чем-то низким, как 5, что 32 раза до этого больше не работает (это еще аргумент, достаточный для того, чтобы это была плохая практика, я не защищаю эту практику, просто объясняя, почему это работает) для 32-битного int мы, конечно, должны были бы использовать ++ 2 ^ 32 раза, прежде чем это станет проблемой. С --, но это приведет только к false, если я начал со значения 1 для true или начал с 0 и использовал ++ ровно один раз раньше.

Это другое значение, если мы начинаем с значения, которое всего несколько ниже 0. В самом деле, в таком случае мы могли бы хотеть ++ привести к значению false в конце концов, например, в:

int x = -5;
while(++x)
  doSomething(x);

Однако этот пример рассматривает x как int всюду, кроме условного, поэтому он эквивалентен:

int x = -5;
while(++x != 0)
  doSomething(x);

Что отличается от использования x как логического.

Ответ 2

ANSI ISO IEC 14882 2003 (С++ 03):

5.2.6-2

Операнд постфикса - это уменьшается по аналогии с постфиксным ++, за исключением того, что операнд не должен иметь тип bool. [Примечание: для приращение префиксов и декремент, см. 5.3.2. ]

И неудивительно...

5.3.2-2

Операнд префикса - изменен путем вычитания 1. Операнд должен не быть типа bool. Требования на операнде префикса - и свойства его результата в противном случае такие же, как и для префикса ++. [Заметка: Для приращения и уменьшения постфикса, см. 5.2.6. ]

Также в 5.6.2-1 и 5.3.2-1 упоминается, что ++ для bools должно быть истинным, а в Приложении D-1 указано, что ++ на bools устарел.

Ответ 3

В силу исторических причин это было поддержано. Но обратите внимание, что... Использование операнда типа bool с оператором ++ устарело, см. Раздел 5.3.2 в стандарте С++ (n3092)

5.3.2 Инкремент и декремент [expr.pre.incr]

  • Изменен операнд префикса ++ добавив 1 или установите значение true, если оно bool (это использование устарело). операнд должен быть модифицируемым значением lvalue. Тип операнда должен быть арифметический тип или указатель на полностью определенный тип объекта. результатом является обновленный операнд; это lvalue, и это бит-поле, если операнд - это бит-поле. Если x равно не типа bool, выражение ++ x эквивалентно x + = 1 [Примечание: см. обсуждения сложения (5.7) и (5.17) для информация о конверсиях. -end note ]
  • Операнд префикса - изменен путем вычитания 1. Операнд должен не быть типа bool. Требования на операнде префикса - и свойства его результата в противном случае те же, что и в префиксе ++.

Ответ 4

  • Со старыми стандартами (С++ 98) это не ошибка.
  • С новыми стандартами приращение логического значения устарело. (С++ 11)
  • Вы можете использовать инкремент с булевым значением до С++ 17.