Is the operation "false < true" well defined?

12,662

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.

Share:
12,662

Related videos on Youtube

duncan
Author by

duncan

Updated on June 02, 2022

Comments

  • duncan
    duncan almost 2 years

    Does the C++ specification define:

    1. the existence of the 'less than' operator for boolean parameters, and if so,
    2. 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
      Deduplicator over 9 years
      g++-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
      Angew is no longer proud of SO over 9 years
      @Ulterior There are valid uses. Such as using std::min on std::vector<bool> as &&.
    • Mark Ransom
      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
      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
      Theodore Norvell over 9 years
      A disturbing consequence is that p <= q means p implies q when p and q are of type bool!
    • Technophile
      Technophile over 9 years
      @TheodoreNorvell, I'm not clear on what you find disturbing about that. Could you say a bit more?
    • Eliah Kagan
      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
      Theodore Norvell over 9 years
      @Technophile Exactly as Eliah said. p <= q looks like q implies p, but in fact means p implies q.
    • devdimi
      devdimi over 9 years
      Be very careful with this if you interact with COM and/or Sql Server as they sometimes define true as -1.
    • Fred Mitchell
      Fred Mitchell over 9 years
      Apparently 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
      Scott Solmer over 9 years
      "is this legislated by the C++..." I sure hope programs don't start writing laws...
    • Shafik Yaghmour
      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.
    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
    KRyan over 9 years
    I like that this answer is shorter than Shafik's, but I think the key point that false is defined as 0 and true is defined as 1 in the standard (rather than just by common practice) needs evidence to back it up.
  • Mark Ransom
    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 as 0 for false and 1 for true. I wouldn't be surprised if you can find it in K+R.
  • KRyan
    KRyan over 9 years
    @MarkRansom huh, for some reason I thought C had bool from the start (though I realize 0 and 1 were used before bool 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
    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 type int."
  • MSalters
    MSalters over 9 years
    The biggest problem IIRC was that in K&R, enum bool { false = 0, true = 1} was legal but didn't define an operator<.
  • Admin
    Admin over 9 years
    Nice, 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
    chris about 9 years
    Not 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
    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
    chris about 9 years
    Yeah, the promotion is the first thing to happen either way.