Ist die Operation "false <true" gut definiert?

153

Definiert die C ++ - Spezifikation:

  1. die Existenz des Operators 'kleiner als' für boolesche Parameter, und wenn ja,
  2. das Ergebnis der 4 Parameter Permutationen?

Mit anderen Worten, sind die Ergebnisse der folgenden Operationen durch die Spezifikation definiert?

false < false
false < true
true < false
true < true

In meinem Setup (Centos 7, gcc 4.8.2) spuckt der folgende Code aus, was ich erwarten würde (angesichts der Geschichte von C, in der false als 0 und true als 1 dargestellt wird):

false < false = false
false < true = true
true < false = false
true < true = false

Obwohl ich mir ziemlich sicher bin, dass die meisten (alle?) Compiler die gleiche Ausgabe liefern, ist dies in der C ++ - Spezifikation gesetzlich geregelt? Oder darf ein verschleierter, aber spezifikationskonformer Compiler entscheiden, dass wahr weniger als falsch ist?

#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;
}
Duncan
quelle
6
@Ulterior Es gibt gültige Verwendungen. Wie die Verwendung von std::minauf std::vector<bool>wie &&.
Angew ist nicht mehr stolz auf SO
19
@Ulterior Wenn Sie eine gute Frage herausfinden können, die nach all den Jahren von StackOverflow noch nicht gestellt wurde, verdienen Sie einige Punkte. Es ist kein Trolling.
Mark Ransom
35
@Ulterior Die Motivation zum Fragen ist echt: Ich bin ziemlich neu in C ++ (komme aus C) und möchte einige Objekte in einem std :: set <> speichern. Meine Implementierung des Operators <meines Objekts basiert hauptsächlich auf einer booleschen Eigenschaft des Objekts, gefolgt von anderen sekundären identifizierenden Eigenschaften. Wenn ich über die Menge iteriere, möchte ich sichergehen, dass die 'falschen' Objekte an erster Stelle stehen. Während es hier und jetzt für mich funktioniert, suche ich nach Sicherheit, dass es garantiert plattformübergreifend (einschließlich eingebetteter) funktioniert, ohne unnötig auf die Verwendung von (a? 1: 0) oder ähnlichem in <meines Objekts zurückgreifen zu müssen Operator.
Duncan
26
Eine beunruhigende Konsequenz ist , dass p <= qMittel , p implies qwenn pund qvom Typ Bool ist!
Theodore Norvell
4
@Technophile Vermutlich ist es störend, dass <=dies versehentlich als linker Pfeil gelesen werden kann und dass der "nur wenn" (dh "[materiell] impliziert") rechte Pfeil manchmal ähnlich gesetzt oder informell geschrieben ist wie =>(dh mit einem doppelten Schaft ähnlich =). . Ein linker Pfeil wird sogar manchmal als "wenn" gelesen, obwohl ich glaube, dass dies weitaus seltener ist als die Verwendung eines rechten Pfeils für "nur wenn".
Eliah Kagan

Antworten:

207

TL; DR:

Die Operationen sind gemäß dem Entwurf des C ++ - Standards gut definiert.

Einzelheiten

Wir können sehen , dass von dem Teilwert Entwurf C ++ Standard Abschnitt 5.9 Vergleichsoperatoren , die sagt ( Hervorhebung von mir für die Zukunft ):

Die Operanden müssen vom Typ Arithmetik , Aufzählung oder Zeiger oder vom Typ std :: nullptr_t sein. Die Operatoren <(kleiner als),> (größer als), <= (kleiner als oder gleich) und> = (größer als oder gleich) ergeben alle falsch oder wahr. Der Typ des Ergebnisses ist bool

und Bools sind arithematische Typen aus 3.9.1 Grundtypen

Die Typen bool , char, char16_t, char32_t, wchar_t und die vorzeichenbehafteten und vorzeichenlosen Ganzzahltypen werden zusammen als integrale Typen bezeichnet.

und

Integrale und schwebende Typen werden zusammen als arithmetische Typen bezeichnet.

und trueund falsesind boolesche Literale von 2.14.6booleschen Literalen:

boolean-literal:
    false
    true

Zurück zum Abschnitt 5.9, um die Mechanik der Vergleichsoperatoren weiter zu sehen, heißt es:

Die üblichen arithmetischen Konvertierungen werden für Operanden vom Typ Arithmetik oder Aufzählung durchgeführt.

Die üblichen arithmetischen Umrechnungen werden in folgenden Abschnitten behandelt 5:

Andernfalls werden die integralen Beförderungen (4.5) für beide Operanden durchgeführt

und Abschnitt 4.5sagt:

Ein Wert vom Typ bool kann in einen Wert vom Typ int konvertiert werden, wobei false zu Null und true zu Eins wird.

und so die Ausdrücke:

false < false
false < true
true < false
true < true

mit diesen Regeln werden:

0 < 0
0 < 1
1 < 0
1 < 1
Shafik Yaghmour
quelle
6
Schön, das ist ungefähr so ​​explizit wie jede Antwort sein könnte, obwohl es immer noch leicht zu lesen ist. Ein Nit: Ich glaube , Sie den falschen „Typ“ bolded: „Die Operanden arithmetische haben sollen , Aufzählung oder Zeigertyp . Oder Typ std :: nullptr_t“ Das Hinzufügen von Klammern zur Verdeutlichung ergibt ((Arithmetik, Aufzählung oder Zeiger) Typ) oder (Typ std :: nullptr_t).
Nicht, dass es Ihre Antwort ändert, aber N3485 [überbaut] / 12: Für jedes Paar heraufgestufter arithmetischer Typen L und R existieren Kandidatenoperatorfunktionen der Form ... bool operator <(L, R); - Werden die Argumente, die vor den von Ihnen zitierten Regeln beworben wurden, nicht überhaupt angewendet?
Chris
@chris Ich bin mit diesem Abschnitt nicht besonders vertraut, daher müsste ich darüber nachdenken, aber ich glaube nicht, dass sich die Antwort von dem ändert, was ich sehen kann.
Shafik Yaghmour
Ja, die Promotion ist das erste, was so oder so passiert.
Chris
63

Boolesche Werte unterliegen den üblichen ganzzahligen Heraufstufungen, falsedefiniert als 0und truedefiniert als 1. Das macht alle Vergleiche gut definiert.

Mark Ransom
quelle
2
... und Vergleichsoperatoren werden angegeben, um die üblichen arithmetischen Konvertierungen (einschließlich ganzzahliger Heraufstufungen) für Operanden vom arithmetischen oder Aufzählungstyp durchzuführen.
TC
5
Ich mag es, dass diese Antwort kürzer ist als die von Shafik, aber ich denke, dass der Schlüsselpunkt, falseder als Standard definiert ist 0und truewie 1 im Standard definiert ist (und nicht nur durch gängige Praxis), Beweise benötigt, um dies zu belegen.
KRyan
@KRyan was, du wirst mein Wort nicht dafür nehmen? :) Bevor es einen boolTyp gab, bevor es überhaupt C ++ gab, wurde das Ergebnis einer booleschen Operation als 0für falsch und 1für wahr definiert. Es würde mich nicht wundern, wenn Sie es in K + R finden können.
Mark Ransom
1
@KRyan Ich kann nicht ganz bis K + R zurückgehen, aber ich habe meine Kopie des ANSI C-Standards von 1990 ausgegraben. In Abschnitt 6.3.8 heißt es: "Jeder der Operatoren <(kleiner als), >(größer als), <=(kleiner als oder gleich) und >=(größer als oder gleich) muss 1 ergeben, wenn die angegebene Beziehung wahr ist, und 0, wenn dies der Fall ist." false. Das Ergebnis hat den Typ int. "
Mark Ransom
1
Das größte Problem IIRC war, dass in K & R enum bool { false = 0, true = 1}legal war, aber keine definiert operator<.
MSalters
22

Nach dem C ++ Standard (5.9 Vergleichsoperatoren)

2 Die üblichen arithmetischen Konvertierungen werden für Operanden vom Typ Arithmetik oder Aufzählung durchgeführt.

und

1 ... Der Typ des Ergebnisses ist bool.

und (3.9.1 Grundtypen)

6 Werte vom Typ Bool sind entweder wahr oder falsch.49 [Hinweis: Es gibt keine vorzeichenbehafteten, vorzeichenlosen, kurzen oder langen Bool-Typen oder -Werte. —End note] Werte vom Typ bool nehmen an integralen Werbeaktionen teil (4.5).

und (4.5 Integrale Werbeaktionen)

6 Ein Wert vom Typ bool kann in einen Wert vom Typ int konvertiert werden, wobei false zu Null und true zu Eins wird .

In all Ihren Beispielen wird true in int 1 und false in int 0 konvertiert

Diese Ausdrücke

false < false
false < true
true < false
true < true

sind völlig gleichwertig mit

0 < 0
0 < 1
1 < 0
1 < 1
Vlad aus Moskau
quelle
8

Boolean falseist äquivalent zu int 0und Boolean trueist äquivalent zu int 1. Dies erklärt, warum der Ausdruck false < true=> 0 < 1der einzige ist, der zurückgibt true.

Blindstealer
quelle