Вызов операторов преобразования
В чем причина следующего поведения?
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
, это выбранное преобразование.