Почему преобразование в ссылку мешает конвертации в bool?
Кажется, что если у меня есть оператор преобразования в ссылке, этот оператор будет иметь приоритет перед преобразованием в bool
. Почему это происходит, и как я могу его исправить?
(Если это имеет значение, я использую GCC 4.5. Я проверил на ideone, что такое же поведение найдено в GCC-4.7.2.)
Предположим следующее:
class B {
protected:
const int a_;
int b_;
B (int b, int a) : a_(a), b_(b) {}
public:
operator bool () const { return b_ == a_; }
};
class D1 : public B {
public:
D1 (int b = 0, int a = 0) : B(b, a) {}
operator int () const { return b_; }
};
class D2 : public B {
public:
D2 (int b = 0, int a = 0) : B(b, a) {}
operator int & () { return b_; }
};
Затем предположим, что они используются в простой программе:
int main () {
if (D1 d1a = D1('a', 'a')) std::cout << "d1a\n";
if (D1 d1b = D1('b', 'a')) std::cout << "d1b\n";
if (D2 d2a = D2('a', 'a')) std::cout << "d2a\n";
if (D2 d2b = D2('b', 'a')) std::cout << "d2b\n";
return 0;
}
Выход этой программы:
d1a
d2a
d2b
Обратите внимание, что d1b
не находится на выходе, что означает, что преобразование в bool
работало так, как я ожидал, для D1
. Но для D2
кажется, что преобразование в ссылочный тип имеет приоритет над преобразованием bool
. Почему это случилось? Есть ли простое изменение, которое я могу сделать для D2
, чтобы преобразование bool
имело приоритет в проверке if
?
В настоящее время я использую D1
и добавляю к нему оператор присваивания для достижения поведения ссылки.
Ответы
Ответ 1
Собственно, он не имеет ничего общего с int&
, это вопрос const
-ness:
operator bool () const { return b_ == a_; }
/* ^^^^^ */
/* vvvvv */
operator int & () { return b_; }
d2a
- это D2
, а не const D2
, поэтому оператор неконстантного преобразования лучше подходит. Если вы напишете его как
operator const int & () const { return b_; }
вы получите ожидаемое поведение, см. http://ideone.com/vPPPYV.
Обратите внимание, что operator const int&
не будет вмешиваться, даже если вы используете версии const
ваших объектов, следующие строки все равно приведут к вашему ожидаемому поведению (см. http://ideone.com/DTE0xH):
if (const D1 d1a = D1('a', 'a')) std::cout << "d1a\n";
if (const D1 d1b = D1('b', 'a')) std::cout << "d1b\n";
if (const D2 d2a = D2('a', 'a')) std::cout << "d2a\n";
if (const D2 d2b = D2('b', 'a')) std::cout << "d2b\n";
Ответ 2
Это
D1 d1a = D1('a', 'a');
D1 d1b = D1('b', 'a');
D2 d2a = D2('a', 'a');
D2 d2b = D2('b', 'a');
if (d1a) std::cout << "d1a\n";
if (d1b) std::cout << "d1b\n";
if (d2a) std::cout << "d2a\n";
if (d2b) std::cout << "d2b\n";
печатает
d1a
d2a
для меня.
У вас есть
if (D2 d2a = D2('a', 'a')) std::cout << "d2a\n";
if (D2 d2a = D2('b', 'a')) std::cout << "d2b\n";
Что произойдет, если вы не используете одно и то же имя в обоих случаях?
Там только d1a
и d2a
на выходе, если я заменю 4-е, если на
if (D2 d2b = D2('b', 'a')) std::cout << "d2b\n";