Is the operation "false < true" well defined?
Solution 1
TL;DR:
The operations are well defined according to the draft C++ standard.
Details
We can see that by going to the draft C++ standard section 5.9
Relational operators which says (emphasis mine going forward):
The operands shall have arithmetic, enumeration, or pointer type, or type std::nullptr_t. The operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) all yield false or true. The type of the result is bool
and bools are arithematic types from 3.9.1 Fundamental types
Types bool, char, char16_t, char32_t, wchar_t, and the signed and unsigned integer types are collectively called integral types.
and
Integral and floating types are collectively called arithmetic types.
and true
and false
are boolean literals from 2.14.6
Boolean literals:
boolean-literal:
false
true
Going back to section 5.9
to see the mechanics of the relational operators further, it says:
The usual arithmetic conversions are performed on operands of arithmetic or enumeration type.
the usual arithmetic conversions are covered in section 5
which says:
Otherwise, the integral promotions (4.5) shall be performed on both operands
and section 4.5
says:
A prvalue of type bool can be converted to a prvalue of type int, with false becoming zero and true becoming one.
and so the expressions:
false < false
false < true
true < false
true < true
using these rules become:
0 < 0
0 < 1
1 < 0
1 < 1
Solution 2
Boolean values are subject to the usual integer promotions, with false
defined as 0
and true
defined as 1
. That makes all the comparisons well defined.
Solution 3
According to the C++ Standard (5.9 Relational operators)
2 The usual arithmetic conversions are performed on operands of arithmetic or enumeration type.
and
1...The type of the result is bool.
and (3.9.1 Fundamental types)
6 Values of type bool are either true or false.49 [ Note: There are no signed, unsigned, short, or long bool types or values. —end note ] Values of type bool participate in integral promotions (4.5).
and (4.5 Integral promotions)
6 A prvalue of type bool can be converted to a prvalue of type int, with false becoming zero and true becoming one.
So in all your examples true is converted to int 1 and false is converted to int 0
These expressions
false < false
false < true
true < false
true < true
are entirely equivalent to
0 < 0
0 < 1
1 < 0
1 < 1
Solution 4
Boolean false
is equivalent to int 0
, and boolean true
is equivalent to int 1
.
So this explains why the expression false < true
=> 0 < 1
is the only one which returns true
.
Related videos on Youtube
duncan
Updated on June 02, 2022Comments
-
duncan almost 2 years
Does the C++ specification define:
- the existence of the 'less than' operator for boolean parameters, and if so,
- the result of the 4 parameter permutations?
In other words, are the results from the following operations defined by the specification?
false < false false < true true < false true < true
On my setup (Centos 7, gcc 4.8.2) , the code below spits out what I'd expect (given C's history of representing false as 0 and true as 1):
false < false = false false < true = true true < false = false true < true = false
Whilst I'm pretty sure most (all?) compilers will give the same output, is this legislated by the C++ specification? Or is an obfuscating, but specification-compliant compiler allowed to decide that true is less than false?
#include <iostream> const char * s(bool a) { return (a ? "true" : "false"); } void test(bool a, bool b) { std::cout << s(a) << " < " << s(b) << " = " << s(a < b) << std::endl; } int main(int argc, char* argv[]) { test(false, false); test(false, true); test(true, false); test(true, true); return 0; }
-
Deduplicator over 9 yearsg++-4.9.0 and clang++-3.5.0 on Linux think it's unremarkable: coliru.stacked-crooked.com/a/2174ebc466d0c445
-
Angew is no longer proud of SO over 9 years@Ulterior There are valid uses. Such as using
std::min
onstd::vector<bool>
as&&
. -
Mark Ransom over 9 years@Ulterior if you can figure out a good question that hasn't yet been asked after all these years of StackOverflow, you deserve some points. It's not trolling.
-
duncan over 9 years@Ulterior The motivation for asking is genuine: I'm fairly new to C++ (coming from C) and want to store some objects in a std::set<>. My implementation of my object's < operator is primarily based on a boolean property of the object, followed by other secondary identifying properties. When iterating over the set, I want to be sure the 'false' objects come first. While it works for me here and now, I'm looking for reassurance it's guaranteed to work across platforms (including embedded ones) without having to resort unnecessarily to the use of (a ? 1 : 0), or similar, in my object's < operator.
-
Theodore Norvell over 9 yearsA disturbing consequence is that
p <= q
meansp implies q
whenp
andq
are of type bool! -
Technophile over 9 years@TheodoreNorvell, I'm not clear on what you find disturbing about that. Could you say a bit more?
-
Eliah Kagan over 9 years@Technophile Presumably what's disturbing is that
<=
might be inadvertently read as a leftarrow, and that the "only if" (i.e., "[materially] implies") rightarrow is sometimes typeset or informally written similarly to=>
(i.e., with a doubled shaft resembling=
). A leftarrow is even sometimes read as "if," though I believe this is far less common than the use of a rightarrow for "only if." -
Theodore Norvell over 9 years@Technophile Exactly as Eliah said.
p <= q
looks likeq
impliesp
, but in fact meansp
impliesq
. -
devdimi over 9 yearsBe very careful with this if you interact with COM and/or Sql Server as they sometimes define true as -1.
-
Fred Mitchell over 9 yearsApparently it is well defined. That is sad. Like a language striving too hard to be popular. While it might be a convenience to "order" true and false, it is logically absurd. So if ordering true and false is a design consideration in a model, IMO, the author should be forced to choose the ordering explicitly. Heck, the next step might be false or true is less than true or true - because two true beats one true.
-
Scott Solmer over 9 years"is this legislated by the C++..." I sure hope programs don't start writing laws...
-
Shafik Yaghmour over 9 years@Okuma.Scott many compilers have extensions that are not part of the standard. Also there are areas where the standard declares that the behavior is implementation defined(different from undefined behavior) which means it could vary from compiler to compiler and still be allowed by the standard. So this is an important distinction and this type of question usually makes it a language lawyer question.
-
T.C. over 9 years...and relational operators are specified to perform the usual arithmetic conversions (which includes integer promotions) on operands of arithmetic or enumeration type.
-
KRyan over 9 yearsI like that this answer is shorter than Shafik's, but I think the key point that
false
is defined as0
andtrue
is defined as1
in the standard (rather than just by common practice) needs evidence to back it up. -
Mark Ransom over 9 years@KRyan what, you're not going to take my word for it? :) Before there was a
bool
type, before there was even C++, the result of a boolean operation was defined as0
for false and1
for true. I wouldn't be surprised if you can find it in K+R. -
KRyan over 9 years@MarkRansom huh, for some reason I thought C had
bool
from the start (though I realize0
and1
were used beforebool
existed in earlier languages). But then I've only so much as seen K+R code once in my life, so my knowledge of that history is suspect. -
Mark Ransom over 9 years@KRyan I can't go back quite as far as K+R, but I dug out my copy of the 1990 ANSI C Standard. Section 6.3.8 says "Each of the operators
<
(less than),>
(greater than),<=
(less than or equal to), and>=
(greater than or equal to) shall yield 1 if the specified relation is true and 0 if it is false. The result has typeint
." -
MSalters over 9 yearsThe biggest problem IIRC was that in K&R,
enum bool { false = 0, true = 1}
was legal but didn't define anoperator<
. -
Admin over 9 yearsNice, that's about as explicit as any answer could possibly be, while still easy to read. A nit: I think you bolded the wrong "type": "The operands shall have arithmetic, enumeration, or pointer type, or type std::nullptr_t." Adding parentheses for clarity gives ((arithmetic, enumeration, or pointer) type) or (type std::nullptr_t).
-
chris about 9 yearsNot that it changes your answer, but N3485 [over.built]/12: For every pair of promoted arithmetic types L and R, there exist candidate operator functions of the form ... bool operator<(L , R ); - Aren't the arguments promoted before the rules you cite even apply?
-
Shafik Yaghmour about 9 years@chris I am not super familiar with that section so I would have to think about it but I don't think the answer changes from what I can see.
-
chris about 9 yearsYeah, the promotion is the first thing to happen either way.