Classification: |
C++ |
Category: |
Development |
Created: |
09/20/2002 |
Modified: |
12/16/2002 |
Number: |
FAQ-0824 |
Platform: |
Not Applicable |
|
Question: My code fails to link because there is no implementation of an overloaded operator== function. This function is defined in
e32std.h inside #if !defined(__BOOL_NO_TRUE_TRAP__), but I can't find the implementation anywhere. What's going on?
Answer: The section of e32std.h is as follows: #if !defined(__BOOL_NO_TRUE_TRAP__) TBool operator==(TTrue,volatile const TBool); TBool operator==(volatile const TBool,TTrue); TBool operator!=(TTrue,volatile const TBool); TBool operator!=(volatile const TBool,TTrue); #endif
This exists as a deliberate mechanism for getting the compiler to tell you if you make a classic coding mistake such as
if (myTBool != theirTBool) { doSomething(); }
The TBool type is actually an integer rather than a true C++ boolean, and so any non-zero value means "true" and equality
comparisons between the values don't give the same result as logical comparisons. The above code is correctly written as
if ((myTBool && !theirTBool) || (theirTBool && !myTBool)) { doSomething(); }
Here is the original reasoning behind the definitions of ETrue and EFalse, and the creation of the decoy operators. ------------------------ In addition, we would like to trap the existing conditionals converting truth values into TBool. They would only serve to
waste space as well as cycles.
The proposed new definition is:
typedef int TBool;
enum TFalse {EFalse=FALSE};
enum TTrue {ETrue=TRUE};
Making EFalse and ETrue values of different types is the key to trapping illegal use, and does not make any difference otherwise.
These definitions in themselves will cause the offending conditionals to fail to compile, but not comparisons involving ETrue. To trap those, we propose to exploit the overload resolution and ambiguity rules.
Introducing an alternative comparison operator involving "similar conversions" results in an ambiguous call when a TBool and a TTrue are compared, as follows:
#if !defined(__BOOL_NO_TRUE_TRAP__)
TBool operator==(TTrue,volatile const TBool);
TBool operator==(volatile const TBool,TTrue);
TBool operator!=(TTrue,volatile const TBool);
TBool operator!=(volatile const TBool,TTrue);
#endif
Note that there is no point in defining these operators, declaring them is sufficient. I find it useful not to use argument
names in a case like this.
The choice of volatile const TBool is motivated by the speculation that instances of this exact type would be thin on the ground, and that any TBool value would
therefore require at least one--trivial--conversion to match the argument. The C++ ARM is a bit on the vague side as to the
overload resolution rules. Introducing these operators causes the desired ambiguity using MSVC, but it might not do so using
a different compiler. The __BOOL_NO_TRUE_TRAP__ macro serves to be able to turn the operators off selectively, in case a compiler chokes on them. Or even as a migration
tool: defining it for selected compilation units would allow ETrue comparisons to be phased out over a period of time.
------------------------
|