-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expression is evaluated twice when operator&&(bool, decltype(expr)) is defined #574
Comments
Cast expression to bool to prevent custom && from defeating short-circuiting
I never got back to you about this. |
Actually I'm fairly confident that this should work for you. I've pushed a commit with the change in. |
Hi Phil. I suggested the original fix for compatibility with a custom However, I have since removed the && operator overload for my type as I
|
The problem with the I put together a little test case for this which reproduced your original issue when I didn't use the cast or the So I'm inclined to leave things as they are here. If anyone else hits problems with it I'll consider reverting back to the original, though. Thanks for taking the time to respond - especially given that the original issue no longer applies to you! |
The problem is that my type overloads the ! operator to produce an object
|
Cast expression to bool to prevent custom && from defeating short-circuiting
I tested this recently with a custom class
with tests
and couldn't reproduce the problem. If no-one can confirm it still exists, I am going to close it. |
Ah but it is reproducible if you take out the |
although I'm not sure how this is meant to be used in an assert if there's no way to interpret it as a bool. If @hpesoj is still watching perhaps he can comment on how well @horenmar's example captures the problem (or if, indeed, there is still a problem). |
I think what @hpesoj meant was that zzyzx operator && (bool lhs, const tester& rhs); if it exists, unless you force the conversion of |
Originally, yes, @lightmare. |
Well, when a user writes Foo foo;
CHECK(foo); we can safely assume X operator && (bool a, const Foo& b); it will be selected by overload resolution, because it doesn't require any user-defined conversion. The compiler will not convert |
In other words,
|
@lightmare Problem with I also managed to send current master into infinite loop: (Compiled with VS2015, Update 3) struct from {
from& operator!() {
std::cout << "Operator!\n";
return *this;
}
operator bool() const {
std::cout << "Bool conversion -- from\n";
return true;
}
};
struct to {
operator bool() const {
std::cout << "Bool conversion -- to\n";
return true;
}
};
to operator&&(bool lhs, const from& rhs) {
std::cout << "operator&&\n";
return{};
}
TEST_CASE("Custom &&") {
from f;
REQUIRE(f);
} |
Yes, |
I should've asked this much earlier, but what exactly is the purpose of "it forces the compiler to give it a look"? In the So that suggests another alternative without introducing more overloaded operators: false && ((expr) ? true : false)
// and another that just occurred to me along the way
false && sizeof(expr) but I wonder why any of this would be needed in the first place... 😖 |
@hpesoj thanks - so you do have a bool operator? (explicit or implicit?). @lightmare the expression that gets evaluated is the one that is decomposed by Catch, then reassembled. Because of the way some literals (particularly integers) are captured by template, along with some of the machinery in Catch to deal with that, the expression that is actually evaluated on reassembly may not be exactly the same. So to make sure any warnings that might be emitted for the actual expression that are not for the reconstucted expression this technique forces the compiler to also evaluated the original expression as well. There is another way I was toying with:
But I think I like the sizeof one even more (with one small change - compare the result to another integer to avoid int-conversion-to-bool warnings)! |
My type was modelling a boolean value, so it had an implicit |
Right, I realized that after posting, and also that the } while ( sizeof(expr) < 0 ); won't produce another warning; tried that with gcc and although } while ( exprAsBool( sizeof(expr) ) );
// I'd rename exprAsBool => alwaysFalse |
This line assumes the built-in
&&
is used. If a user-definedoperator&&
is used, the expression is not short-circuited, andexpr
is evaluated here (and twice overall). I know that overloading&&
is not generally recommended, but I think this corner-case can be fixed by explicitly castingexpr
tobool
:The text was updated successfully, but these errors were encountered: