Вызов операторов преобразования

В чем причина следующего поведения?

class BoolWrapper
{
public:
    BoolWrapper(bool value) : value(value) {}

    operator bool() const { return value; }
    operator int() const { return (int) value; }

private:
    bool value;
};


BoolWrapper bw(true);

if (bw) { ... }            // invokes operator bool()
if (bw == true) { ... }    // invokes operator int() -- why?

Ожидается ли такое поведение? (Использование GCC 4.7.2.)

Ответ 1

Ваши ожидания основаны на вашем убеждении, что язык уже знает, как сравнить два значения bool. На самом деле это, как ни удивительно, звучит. Точнее, язык "не знает", как это сделать напрямую.

На концептуальном уровне С++ не имеет специального встроенного оператора сравнения равенства для сравнений bool vs. bool. Даже когда вы пишете true == false в своем коде, он действительно интерпретируется языком как (int) true == (int) false. Неявное преобразование в int вводится правилами обычных арифметических преобразований, а сравнение int vs. int используется впоследствии.

Самый непосредственный встроенный оператор, который может сравнивать два значения bool, - это сравнение для int vs. int. Это оператор, который компилятор также пытается использовать в вашем случае. Тот же самый оператор будет использоваться для сравнений char vs. char и short vs. short.

Другими словами, единственный способ, которым компилятор может использовать ваш оператор преобразования bool в выражении bw == true, - это сделать

(int)(bool) bw == (int) true

Это, конечно, менее "оптимальный", чем прямой

(int) bw == (int) true

Это логика, которая побуждает язык выбирать последний вариант.

Ответ 2

От 5/9:

Многие двоичные операторы, которые ожидают операнды арифметики или тип перечисления вызывает преобразования и дает результаты в аналогичных путь. Цель состоит в том, чтобы дать общий тип, который также является типом результат. Этот шаблон называется обычным арифметическим преобразованием, которые определяются следующим образом:

[Некоторые элементы с плавающей запятой, которые не имеют значения.]

В противном случае интегральные акции (4.5) должны выполняться на обоих операнды.

И из 3.9.1/6 мы видим, что bool имеет право на интегральную рекламу:

Значения типа bool являются либо истинными, либо ложными .42) [Примечание: нет подписанные, неподписанные, короткие или длинные типы или значения bool. ] Как описано ниже, значения bool ведут себя как целые типы. Значения типа bool участвовать в интегральных акциях (4.5).

Ответ 3

В первом случае предложение if ожидает условие bool, поэтому это выбранное преобразование.

Во втором случае вы запрашиваете сравнение между BoolWrapper и a bool. Поскольку для этого не существует перегрузки operator ==, компилятор должен преобразовать эти аргументы в подходящие. Согласно стандарту (раздел 4.5, Интегральные акции) предпочтительным интегральным типом для конверсий является int. Поскольку BoolWrapper и bool могут быть преобразованы в int, это выбранное преобразование.