views:

74

answers:

3

This question is related to this question. The following code compiles fine VC9 compiler but gives the error when compied with Comeau online. Can anybody tell me which one is correct and what is the meaning of the error?

error: ambiguous "?" operation: second operand of type "TypesafeBool" can be converted to third operand type "bool", and vice versa TypesafeBool b = (1==1) ? f() : false;

class TypesafeBool
{
private:
    bool m_bValue;
    struct Bool_ { 
        int m_nValue; 
    };
    typedef int Bool_::* bool_;
    inline bool_ True() const { return &Bool_::m_nValue; }
    inline bool_ False() const { return 0; }

public:
    TypesafeBool( const bool bValue ) : m_bValue( bValue ){}
    operator bool_() const { return m_bValue ? True() : False(); }
};

TypesafeBool f()
{
    return TypesafeBool(true);
}

int main()
{
    TypesafeBool b = (1==1) ? f() : false;
}
+8  A: 

The error is that the ternary operator must have a single type, and your expression (1=1) ? f() : false has two types -- f() has type TypesafeBool and false has type bool. You can convert between them, but Comeau doesn't know which you want to use. To resolve it, cast one of the sides of the ternary to the type of the other: (1=1) ? f() : TypesafeBool(false).

Comeau is correct here, as while it's obvious to the observer what type the result should take, the ternary expression needs to have a single type on its own, without reference to what it's used in, and the type it should pick is ambiguous.

Andrew Aylett
Great answer. So it's the fact that you can convert both ways that causes the problem. It's a real shame a since what I wanted was a drop-in replacement for `bool` that would do this extra checking for me. I can't be littering the code with casts all over the place though.
jkp
Section 5.16/3 talks about the rules in pretty sleepy details :)
Chubsdad
@jkp: In some cases you can limit one of the conversions --in this case it would have to be the implicit `bool`->`TypesafeBool` conversion to avoid the ambiguity.
David Rodríguez - dribeas
A: 

Both cases for operator? result must have the same type. The natural type for them is TypesafeBool and bool. As there is an implicit conversion from bool to TypesafeBool and from bool to TypesafeBool, there is an ambiguity which should be applied.

C++ rules prevent the fact that the result is then used in a context where a TypesafeBool is expected or the fact that the result is known to be taken into account to prefer the second way

TypesafeBool b = (1 == 1)? f() : TypesafeBool(false);

should work.

AProgrammer
A: 

To follow on from @hype's comment, this article also puts forward the same idea but with the constructor marked explicit. This removes your ambiguity.

Note that your example would then work fine provided you change the initialisation of b to

TypesafeBool b( (1==1) ? f() : false );

since the = syntax is not allowed to invoke TypesafeBool( bool ) when it's marked explicit (because it's technically a composition of two constructors).

Troubadour