[signals2] Test failure in C++11 (trivial fix for incorrect usage of boost::optional)
I have the following errors: "clang++-3.4" -c -x c++ -std=c++11 -stdlib=libc++ -O0 -g -fno-inline -Wall -g -DBOOST_ALL_NO_LIB=1 -DBOOST_TEST_NO_AUTO_LINK=1 -I".." -o "/home/ben/development/boost/test/build/results/boost/bin.v2/libs/signals2/test/signal_test.test/clang-linux-3.4~c11_libc++/debug/link-static/signal_test.o" "../libs/signals2/test/signal_test.cpp" ../libs/signals2/test/signal_test.cpp:32:16: error: invalid operands to binary expression ('boost::optional<int>' and 'int') if(max == false) max = *first; ~~~ ^ ~~~~~ "clang++-3.4" -c -x c++ -std=c++11 -stdlib=libc++ -O0 -g -fno-inline -Wall -g -DBOOST_ALL_NO_LIB=1 -DBOOST_TEST_NO_AUTO_LINK=1 -I".." -o "/home/ben/development/boost/test/build/results/boost/bin.v2/libs/signals2/test/track_test.test/clang-linux-3.4~c11_libc++/debug/link-static/track_test.o" "../libs/signals2/test/track_test.cpp" ../libs/signals2/test/track_test.cpp:36:14: error: invalid operands to binary expression ('boost::optional<int>' and 'int') if(max == false) Richard smith explains the problem here: http://llvm.org/bugs/show_bug.cgi?id=18180#4 "OK, I see what's happening -- in Clang 3.3 and GCC 4.8, 'false' is being treated as a null pointer constant. boost::optional implicitly converts to an "unspecified-bool-type" that happens to be a pointer-to-member type, and thus can be compared against a null pointer constant via the built-in operator!=(pointer-to-member, pointer-to-member) overload. In C++11 onwards, 'false' isn't a null pointer constant any more, so this comparison is no longer valid. Clang 3.3 and GCC 4.8 don't implement that rule; Clang 3.4 does." The trivial fix is to change the if statements at: ../libs/signals2/test/signal_test.cpp:32:16: ../libs/signals2/test/track_test.cpp:36:14: to if(!max) rather than if(max == false). Ben
On Wednesday 26 February 2014 11:58:52 Ben Pope wrote:
On Wednesday, December 11, 2013 03:26 PM, Ben Pope wrote:
The trivial fix is to change the if statements at: .../libs/signals2/test/signal_test.cpp:32:16: .../libs/signals2/test/track_test.cpp:36:14:
to if(!max) rather than if(max == false).
Ping
You could create a pull request or Trac ticket so that it doesn't get lost.
On Wednesday, February 26, 2014 12:10 PM, Andrey Semashev wrote:
On Wednesday 26 February 2014 11:58:52 Ben Pope wrote:
On Wednesday, December 11, 2013 03:26 PM, Ben Pope wrote:
The trivial fix is to change the if statements at: .../libs/signals2/test/signal_test.cpp:32:16: .../libs/signals2/test/track_test.cpp:36:14:
to if(!max) rather than if(max == false).
Ping
You could create a pull request or Trac ticket so that it doesn't get lost.
On Tue, Feb 25, 2014 at 10:58 PM, Ben Pope
On Wednesday, December 11, 2013 03:26 PM, Ben Pope wrote:
The trivial fix is to change the if statements at: .../libs/signals2/test/signal_test.cpp:32:16: .../libs/signals2/test/track_test.cpp:36:14:
to if(!max) rather than if(max == false).
Thanks for putting in the ticket, I never noticed the original mailing list post back in December. I read the explanation of the problem referred to in the original December post, however it seems to me the bug is in optional's safe-bool implementation under c++11. That is, the expression "max==false" should implicitly convert the optional "max" to a boolean and compile. -- Frank
On 26/02/2014 08:17 p.m., Frank Mori Hess wrote:
On Tue, Feb 25, 2014 at 10:58 PM, Ben Pope
wrote: On Wednesday, December 11, 2013 03:26 PM, Ben Pope wrote:
The trivial fix is to change the if statements at: .../libs/signals2/test/signal_test.cpp:32:16: .../libs/signals2/test/track_test.cpp:36:14:
to if(!max) rather than if(max == false).
Thanks for putting in the ticket, I never noticed the original mailing list post back in December. I read the explanation of the problem referred to in the original December post, however it seems to me the bug is in optional's safe-bool implementation under c++11. That is, the expression "max==false" should implicitly convert the optional "max" to a boolean and compile.
That's incorrect, `false` is not a disengaged `optional`. If you want to write your comparisons that way you should write `max==boost::none` (or `max==std::nullopt` in the standard proposal). Regards, -- Agustín K-ballo Bergé.- http://talesofcpp.fusionfenix.com
Frank Mori Hess wrote:
I read the explanation of the problem referred to in the original December post, however it seems to me the bug is in optional's safe-bool implementation under c++11. That is, the expression "max==false" should implicitly convert the optional "max" to a boolean and compile.
The C++11 "explicit operator bool" feature is stricter than the safe bool idiom. !max is fine, because !x is considered a boolean context for x; max == false is not, because x == y is not a boolean context for x or y.
On Thu, Feb 27, 2014 at 8:14 AM, Peter Dimov
The C++11 "explicit operator bool" feature is stricter than the safe bool idiom. !max is fine, because !x is considered a boolean context for x; max == false is not, because x == y is not a boolean context for x or y.
Yes, but boost::optional doesn't use explicit operator bool, even when compiling under c++11 as far as I know. It is the behavior of optional's safe bool idiom implementation which has changed due to language changes in c++11. Even if optional is changed to use explicit operator bool, does that exclude the possibility of adding free operator== and operator != methods which take one argument as an optional and one argument as a bool? Would such overloads actually introduce any dangerous behavior? -- Frank
On 27/02/2014 08:15 p.m., Frank Mori Hess wrote:
On Thu, Feb 27, 2014 at 8:14 AM, Peter Dimov
wrote: The C++11 "explicit operator bool" feature is stricter than the safe bool idiom. !max is fine, because !x is considered a boolean context for x; max == false is not, because x == y is not a boolean context for x or y.
Even if optional is changed to use explicit operator bool, does that exclude the possibility of adding free operator== and operator != methods which take one argument as an optional and one argument as a bool? Would such overloads actually introduce any dangerous behavior?
What would those overloads do for `optional<bool>`? Regards, -- Agustín K-ballo Bergé.- http://talesofcpp.fusionfenix.com
On Thu, Feb 27, 2014 at 6:20 PM, Agustín K-ballo Bergé
On 27/02/2014 08:15 p.m., Frank Mori Hess wrote:
Even if optional is changed to use explicit operator bool, does that exclude the possibility of adding free operator== and operator != methods which take one argument as an optional and one argument as a bool? Would such overloads actually introduce any dangerous behavior?
What would those overloads do for `optional<bool>`?
Ah, I wasn't aware optional already had overloaded the comparison operators with comparisons of optional<T> vs T. A little unfortunate IMO, it makes optional<bool> a bit of a disaster when any sort of conversion to bool at all is supported. -- Frank
On 28/02/2014 12:33, Quoth Frank Mori Hess:
Ah, I wasn't aware optional already had overloaded the comparison operators with comparisons of optional<T> vs T. A little unfortunate IMO, it makes optional<bool> a bit of a disaster when any sort of conversion to bool at all is supported.
Not really; tristate bool logic with optional<bool> is pretty straightforward. It usually falls into the pattern: if (value == true) { /* do something when true */ } else if (value == false) { /* do something when false */ } else { /* do something when null/none/unknown/unspecified */ } There is a little trap for the unwary where: if (value) { /* either true or false */ } else { /* only null, not false */ } But once you get used to it, I'd hardly call it a "disaster". And it's consistent with the behaviour of other values, eg. optional<int> when zero executes the if block, not the else block.
On Thu, Feb 27, 2014 at 8:45 PM, Gavin Lambert
On 28/02/2014 12:33, Quoth Frank Mori Hess:
Ah, I wasn't aware optional already had overloaded the comparison operators with comparisons of optional<T> vs T. A little unfortunate IMO, it makes optional<bool> a bit of a disaster when any sort of conversion to bool at all is supported.
Not really; tristate bool logic with optional<bool> is pretty straightforward. It usually falls into the pattern:
if (value == true) { /* do something when true */ } else if (value == false) { /* do something when false */ } else { /* do something when null/none/unknown/unspecified */ }
There is a little trap for the unwary where:
if (value) { /* either true or false */ } else { /* only null, not false */ }
But once you get used to it, I'd hardly call it a "disaster".
Nothing is a problem once you get used to it. I apologize for using a bit of hyperbole, let me try again. I consider the following obvious: given two expressions like "!x" and "x==false" we have: desirable behavior: they both compile and mean the same thing. neutral behavior: only one compiles. undesirable behavior: they both compile and mean completely different things. -- Frank
Frank Mori Hess wrote:
Nothing is a problem once you get used to it. I apologize for using a bit of hyperbole, let me try again. I consider the following obvious: given two expressions like "!x" and "x==false" we have:
desirable behavior: they both compile and mean the same thing. neutral behavior: only one compiles. undesirable behavior: they both compile and mean completely different things.
This is obviously a matter of stylistic preference, but still, mine runs contrary to yours. x == false is an anti-pattern and should never be preferred to !x, even when x is bool; similarly, x == true is an anti-pattern and should never be preferred to plain x. Boolean logic doesn't have ==. Nobody prefers ( x == y ) == false to !( x == y ) or x != y, let alone ( x == y ) == true to x == y. And when our original x is not bool but, say, a pointer, x == false is just silly, even though it works.
On Fri, Feb 28, 2014 at 11:26 AM, Peter Dimov
Frank Mori Hess wrote:
Nothing is a problem once you get used to it. I apologize for using a bit of hyperbole, let me try again. I consider the following obvious: given two expressions like "!x" and "x==false" we have:
desirable behavior: they both compile and mean the same thing. neutral behavior: only one compiles. undesirable behavior: they both compile and mean completely different things.
This is obviously a matter of stylistic preference, but still, mine runs contrary to yours. x == false is an anti-pattern and should never be preferred to !x , even when x is bool; similarly, x == true is an anti-pattern and should never be preferred to plain x. Boolean logic doesn't have ==. Nobody prefers ( x == y ) == false to !( x == y ) or x != y, let alone ( x == y ) == true to x == y.
And when our original x is not bool but, say, a pointer, x == false is just silly, even though it works.
Ok, but when you are going over some code and see "x==false", and decide to refactor it to "!x" for all the reasons you've given, you've just broken the code. Because they mean completely different things for optional<bool>. -- Frank
Frank Mori Hess wrote:
Ok, but when you are going over some code and see "x==false", and decide to refactor it to "!x" for all the reasons you've given, you've just broken the code. Because they mean completely different things for optional<bool>.
Well that's correct. But then again, if I decide to refactor 'x == true' into 'x', this can also break the code if x is some esoteric type such as 'int'. :-)
On Fri, Feb 28, 2014 at 1:30 PM, Peter Dimov
Frank Mori Hess wrote:
Ok, but when you are going over some code and see "x==false", and decide to refactor it to "!x" for all the reasons you've given, you've just broken the code. Because they mean completely different things
for optional<bool>.
Well that's correct. But then again, if I decide to refactor 'x == true' into 'x', this can also break the code if x is some esoteric type such as 'int'. :-)
Allright, I'll just make one more quibble then stop my ranting. Someone writing "x==true" where x is an int to test if x is exactly 1 is just bad code in the first place. However, writing "x==true" where x is an optional<bool> is apparently (at least to some as a recent post indicates) the by-design way a value inside an optional<bool> should be compared. -- Frank
On 28 February 2014 13:11, Frank Mori Hess
Allright, I'll just make one more quibble then stop my ranting. Someone writing "x==true" where x is an int to test if x is exactly 1 is just bad code in the first place. However, writing "x==true" where x is an optional<bool> is apparently (at least to some as a recent post indicates) the by-design way a value inside an optional<bool> should be compared.
The optional<T> vs. T comparisons are wanted for containers, as people don't want to pay the cost of constructing an optional just to, say, do a find in a C++1y map. We could always specialize optional<bool>, because that worked oh-so-well for vector... -- Nevin ":-)" Liber mailto:nevin@eviloverlord.com (847) 691-1404
On 1/03/2014 05:26, Quoth Peter Dimov:
This is obviously a matter of stylistic preference, but still, mine runs contrary to yours. x == false is an anti-pattern and should never be preferred to !x, even when x is bool; similarly, x == true is an anti-pattern and should never be preferred to plain x. Boolean logic doesn't have ==. Nobody prefers ( x == y ) == false to !( x == y ) or x != y, let alone ( x == y ) == true to x == y.
FWIW, I've seen official coding styles to explicitly use "x == false" instead of "!x", primarily because it's easier to miss the "!" either when writing or later reviewing the code. At least for "real" bools, the compiler will produce the same code either way; it can get a little more troublesome with overloaded operators (which is of course what prompted this discussion in the first place). "x == true" is banned except when dealing with optional<bool>; for that simply using "x" is preferred, with a fallback to "x != false" where required or if it makes it easier to read. (Where it comes up most often is in using (x != FALSE) where x is a BOOL in the Windows sense, not actually a bool. This avoids a compiler warning.) TLDR: I don't think I agree that "!x" is always preferred over "x == false". (And in the case of optional<bool>, it changes behaviour.)
On Fri, Feb 28, 2014 at 7:38 PM, Frank Mori Hess
On Thu, Feb 27, 2014 at 8:45 PM, Gavin Lambert
wrote: On 28/02/2014 12:33, Quoth Frank Mori Hess:
Ah, I wasn't aware optional already had overloaded the comparison operators with comparisons of optional<T> vs T. A little unfortunate IMO, it makes optional<bool> a bit of a disaster when any sort of conversion to bool at all is supported.
Not really; tristate bool logic with optional<bool> is pretty straightforward. It usually falls into the pattern:
if (value == true) { /* do something when true */ } else if (value == false) { /* do something when false */ } else { /* do something when null/none/unknown/unspecified */ }
There is a little trap for the unwary where:
if (value) { /* either true or false */ } else { /* only null, not false */ }
But once you get used to it, I'd hardly call it a "disaster".
Nothing is a problem once you get used to it. I apologize for using a bit of hyperbole, let me try again. I consider the following obvious: given two expressions like "!x" and "x==false" we have:
desirable behavior: they both compile and mean the same thing.
I don't think I agree with that. IMO, "x==false" should not compile since it has ambiguous interpretation.
neutral behavior: only one compiles.
This one is desirable for me.
undesirable behavior: they both compile and mean completely different things.
On Fri, Feb 28, 2014 at 5:45 AM, Gavin Lambert
On 28/02/2014 12:33, Quoth Frank Mori Hess:
Ah, I wasn't aware optional already had overloaded the comparison operators with comparisons of optional<T> vs T. A little unfortunate IMO, it makes optional<bool> a bit of a disaster when any sort of conversion to bool at all is supported.
Not really; tristate bool logic with optional<bool> is pretty straightforward. It usually falls into the pattern:
if (value == true) { /* do something when true */ } else if (value == false) { /* do something when false */ } else { /* do something when null/none/unknown/unspecified */ }
There is a little trap for the unwary where:
if (value) { /* either true or false */ } else { /* only null, not false */ }
I prefer to check for the value presence first: if (!value) { // value is absent } else if (value.get()) { // value is true } else { // value is false } This way the semantics is pretty obvious.
participants (7)
-
Agustín K-ballo Bergé
-
Andrey Semashev
-
Ben Pope
-
Frank Mori Hess
-
Gavin Lambert
-
Nevin Liber
-
Peter Dimov