How does "contextual conversion" work with the operators `&&` and `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `

From @Xeo, a great c++-faq question c++-faq : c++-faq safe-bool idiom deprecated in C ++ 11? I found out that the safe bool idiom is no longer needed because the custom explicit to bool conversion will be automatically called in contexts where a safe bool was needed in C ++ 03.

However, the possibility of overloading operators such as && , || and ! seems to get around this.

Cases when operator! necessary, except that conversion to bool rare, like operator&& and operator|| , but C ++ expression tree implementations (used for deferred execution and symbolic mathematical methods), you need to override this.

Is "context conversion" performed when the user statement is called? What SFINAE spell is needed to ensure that the definition of operator&& or operator|| will work correctly with both types that implement the "safe bool" and those that are designed for "context conversion"?


To clarify, given:

 class uses_safe_bool { void f() {}; typedef void (uses_safe_bool::* safe_bool)(); public: operator safe_bool() const { return (rand() & 1)? &uses_safe_bool::f: 0; } }; class uses_explicit_bool { public: explicit operator bool() const { return rand() & 1; } }; template<typename T> class deferred_expression { // Not convertible to bool public: T evaluate() const; }; 

What signatures are required for operator|| for which the following expressions are true:

 deferred_expression<bool> db; uses_safe_bool sb; uses_explicit_bool eb; int i; auto test1 = sb || db; auto test2 = eb || db; auto test3 = true || db; auto test4 = false || db; auto test5 = i || db; 

they use another overload:

 auto test6 = db || db; deferred_expression<int> di; auto test7 = di || db; 

and during compilation reject:

 std::string s; auto test7 = s || db; std::vector<int> v; auto test8 = v || db; deferred_expression<std::string> ds; auto test9 = ds || db; 
+4
source share
1 answer

The rule is the same for C ++ 03 (safe-bool idiom) and C ++ 11 (explicit conversion operator): do not overload the Boolean operators for this (so as not to lose the behavior of the short circuit, plus the default work is just fine). The latter will work because the operands of the built-in logical operators have the right to contextual conversion, for example, for && from n3290, 5.14 Logical operator AND [expr.log.and]:

1 && operator groups from left to right. The operands are converted in context mode to the bool type (section 4) .

(emphasis mine, similar text for other operators)


Overloaded operators are regular function calls, so no contextual conversion occurs. Make sure your overloaded Boolean operators are always selected using overload resolution, and you're good to go. For example, neglecting lvalues:

 struct evil { explicit operator bool() const; }; void operator||(evil&&, evil&&); evil e; // built-in operator|| e || e; // overloaded operator|| evil() || evil() 

Note that template<typename Lhs, typename Rhs> void operator||(Lhs&&, Rhs&&); will be selected via ADL if any of the operand types has a class type, regardless of cv-qualifiers and category of values.

+4
source

All Articles