Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does conversion to reference interfere with conversion to bool?

Tags:

c++

It seems that if I have a conversion operator to a reference, this operator will take precedence over a conversion to a bool. Why does this happen, and how can I fix it?

(If it matters, I am using GCC 4.5. I verified on ideone that the same behavior is found with GCC-4.7.2.)

Assume the following:

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_; }
};

Then, assume they are used in a simple program like this:

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;
}

The output of this program is:

d1a
d2a
d2b

Note that d1b is not in the output, which means the conversion to bool worked the way I expected it to for D1. But, for D2, it seems the conversion to the reference type took precedence over the bool conversion. Why did this happen? Is there a simple change I can make to D2 to allow the bool conversion to take precedence in the if check?

Currently, I am using D1 and adding an assignment operator to it to achieve the behavior of a reference.

like image 425
jxh Avatar asked Jul 11 '13 21:07

jxh


2 Answers

Actually, it has nothing to do with int&, it's a matter of const-ness:

operator bool () const { return b_ == a_; }
              /* ^^^^^ */
              /* vvvvv */
operator int & () { return b_; }

d2a is a D2, not a const D2, so the non-const conversion operator is a better fit. If you write it as

operator const int & () const { return b_; }

you will get the expected behaviour, see http://ideone.com/vPPPYV.

Note that operator const int& won't interfere even if you use the const versions of your objects, the following lines would still result in your expected behaviour (see 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";
like image 175
Zeta Avatar answered Oct 01 '22 11:10

Zeta


This

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";

prints

d1a
d2a

for me.

You have

if (D2 d2a = D2('a', 'a')) std::cout << "d2a\n";
if (D2 d2a = D2('b', 'a')) std::cout << "d2b\n";

What happens if you don't use the same name in both cases? There's only d1a and d2a in the output if I replace the 4th if by

if (D2 d2b = D2('b', 'a')) std::cout << "d2b\n";
like image 28
Pixelchemist Avatar answered Oct 01 '22 10:10

Pixelchemist