Ambiguous condition operations

Started by
8 comments, last by CmpDev 16 years, 12 months ago
If I create conversion operators for a class, such as:
operator const float*() const { return FData; }
Then provide a bool or BOOL (int) operator:
operator bool() const { return FData && *FData != 0; }
Then when using the class in a condition such as "if( instance )", the bool operator seems to be the one favored without any compiler complaints. However, if I attempt to use several of the class in the same condition, such as "if( instance_a && instance_b ), I get ambiguous complaints involving the built in && operator. It can't seem to choose between the float* and bool type. Why is it that two together seem to make the operation more complex? And is there any way I can fix the problem without removing one of the conversion operators? Thanks for any help
Advertisement
The number of steps needed to transform the values so that operator && can be applied is the same. So the compiler cannot decide which one to use. However you can provide a special version of operator && that expects two instances of your class to provide a better match (without conversion).
But wouldn't that only fix the specific situation of using the && operator between two of the class type? After doing so, just adding another type of condition brings the problem back:
if( some_x_ptr != null && class_instance )


Do I need to create two global templated operators instead?
template <typename Type>BOOL operator && (const MyClass &a,const Type &b) { return a.BoolCondition() && b; }template <typename Type>BOOL operator && (const Type &b,const MyClass &a) { return a.BoolCondition() && b; }


Or is there a better way to fix it?
Just in case someone gets a strange urge to copy my example operators above, I wanted to point out that I made a horrible mistake by changing the order of parameters (b, a) in the condition for the second example.

It should have been this:
template <typename Type>BOOL operator && (const MyClass &a,const Type &b) { return a.BoolCondition() && b; }template <typename Type>BOOL operator && (const Type &a,const MyClass &b) { return a && b.BoolCondition(); }
It's impossible to correctly overload && or || - C++ provides no facilities to allow functions to optionally evaluate parameters, so the short circuit behaviour of &&/|| can#t be replicated in a user defined function.

This is one of the reasons why it's considered very bad practice to provide conversion operators.
Never, ever, ever overload &&, || or ->. (I don't think it's possible to overload . but if you can, don't do that either). See Meyers, Effective C++ for the reasons why. But just don't do it. Ever.
Actually, you shouldn't overload operator&&, operator|| or operator, according to Meyers.

Overloading operator-> should be fine.
Quote:Original post by Deventer
Overloading operator-> should be fine.


Not only that, overloading operator-> is fundamental to the implementation of the entire iterator concept, which the C++ standard library uses extensively.
Quote:Original post by Kest
... is there any way I can fix the problem without removing one of the conversion operators?


No. Here's a word of wisdom: avoid conversion operators. Make your conversions explicit. It not only helps the reader understand your code (and that could be you, 6 weeks from now), but it avoids problems even seasoned C++ experts sometimes run into when entangling themselves with the myriad promotion, conversion, and resolution rules.

You will notice that the C++ standard library does not make use of conversion operators, except for IOStreams, and those are mostly to avoid breaking existing pre-standard code.

Stephen M. Webb
Professional Free Software Developer

Quote:is there any way I can fix the problem without removing one of the conversion operators?

Give the compiler a helping hand.
Quote:
if( (bool)instance_a && (bool)instance_b )


Also consider what others in this thread have wrote, is there any benifit from having a bool operator(one I might add that is floored) instead of a valid function?

Herb Sutter:
Quote:
Implicit conversions can interfere with overload resolution.

Implicit conversions can silently let "wrong" code compile cleanly.

Avoid writing conversion operators. Avoid non-explicit constructors.


Anyway back to your bool operator
Quote:operator bool() const { return FData && *FData != 0; }

FData is a pointer to float and you are comparing it to an int, not problem there the int gets promoted to a float. But when will !*FData != 0" ever be true?


[Edited by - CmpDev on April 22, 2007 1:52:54 PM]

This topic is closed to new replies.

Advertisement