L'operazione "false <true" è ben definita?


153

La specifica C ++ definisce:

  1. l'esistenza dell'operatore "minore di" per i parametri booleani e, in tal caso,
  2. il risultato delle 4 permutazioni dei parametri?

In altre parole, i risultati delle seguenti operazioni sono definiti dalla specifica?

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

Nel mio setup (Centos 7, gcc 4.8.2), il codice qui sotto sputa quello che mi aspetterei (data la storia di C che rappresenta false come 0 e true come 1):

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

Mentre sono abbastanza sicuro che la maggior parte (tutti?) I compilatori daranno lo stesso output, questo è legiferato dalla specifica C ++? O è un compilatore offuscato, ma conforme alle specifiche, autorizzato a decidere che true è inferiore a 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;
}

6
@Ulterior Ci sono usi validi. Come usare std::minsu std::vector<bool>come &&.
Angew non è più orgoglioso di SO

19
@Ulterior se riesci a capire una buona domanda che non è stata ancora posta dopo tutti questi anni di StackOverflow, ti meriti alcuni punti. Non è la pesca a traina.
Mark Ransom,

35
@Ulterior La motivazione per chiedere è autentica: sono abbastanza nuovo in C ++ (proveniente da C) e voglio archiviare alcuni oggetti in uno std :: set <>. La mia implementazione dell'operatore <del mio oggetto si basa principalmente su una proprietà booleana dell'oggetto, seguita da altre proprietà identificative secondarie. Durante l'iterazione sul set, voglio essere sicuro che gli oggetti "falsi" vengano per primi. Mentre funziona per me qui e ora, sto cercando rassicurazione che funzioni su tutte le piattaforme (comprese quelle incorporate) senza dover ricorrere inutilmente all'utilizzo di (a? 1: 0) o simile, nel mio oggetto < operatore.
Duncan,

26
Una conseguenza inquietante è che p <= qsignifica p implies qquando pe qsono di tipo bool!
Theodore Norvell,

4
@Technophile Presumibilmente ciò che disturba è che <=potrebbe essere inavvertitamente letto come un leftarrow, e che il "solo se" (cioè, [materialmente] implica ") rightarrow è talvolta composto o scritto in modo simile in modo simile =>(cioè, con un albero raddoppiato simile a =) . A volte anche un leftarrow viene letto come "se", anche se credo che questo sia molto meno comune dell'uso di un rightarrow per "solo se".
Eliah Kagan,

Risposte:


207

TL; DR:

Le operazioni sono ben definite secondo il progetto di standard C ++.

Dettagli

Possiamo vederlo andando alla bozza della sezione standard C ++ 5.9 Operatori relazionali che dice ( enfatizzare il mio andare avanti ):

Gli operandi devono avere aritmetica , enumerazione o tipo di puntatore oppure digitare std :: nullptr_t. Gli operatori <(minore di),> (maggiore di), <= (minore o uguale a) e> = (maggiore o uguale a) producono tutti falso o vero. Il tipo di risultato è bool

e i bool sono tipi aritmatici dal 3.9.1 Tipi fondamentali

I tipi bool , char, char16_t, char32_t, wchar_t e i tipi interi con segno e senza segno sono chiamati collettivamente tipi integrali.

e

I tipi integrale e mobile sono chiamati collettivamente tipi aritmetici.

e truee falsesono letterali booleani da 2.14.6letterali booleani:

boolean-literal:
    false
    true

Tornando alla sezione 5.9per vedere ulteriormente la meccanica degli operatori relazionali, si dice:

Le solite conversioni aritmetiche vengono eseguite su operandi di tipo aritmetico o di enumerazione.

le solite conversioni aritmetiche sono trattate nella sezione 5che dice:

In caso contrario, le promozioni integrali (4.5) devono essere eseguite su entrambi gli operandi

e la sezione 4.5dice:

Un valore di tipo bool può essere convertito in un valore di tipo int, con false che diventa zero e true che diventa uno.

e quindi le espressioni:

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

usando queste regole diventano:

0 < 0
0 < 1
1 < 0
1 < 1

6
Bello, è esplicito quanto una risposta potrebbe essere, mentre è ancora facile da leggere. A nit: Penso che tu abbia messo in grassetto il "tipo" sbagliato: "Gli operandi devono avere aritmetica , enumerazione o tipo di puntatore , oppure digitare std :: nullptr_t." L'aggiunta di parentesi per chiarezza fornisce (tipo (aritmetico, enumerazione o puntatore)) o (tipo std :: nullptr_t).

Non che cambi la tua risposta, ma N3485 [over.built] / 12: per ogni coppia di tipi aritmetici promossi L e R, esistono funzioni candidate dell'operatore del modulo ... bool operator <(L, R); - Gli argomenti promossi prima delle regole citate non si applicano nemmeno?
chris,

@chris Non ho molta familiarità con quella sezione, quindi dovrei pensarci, ma non penso che la risposta cambi da ciò che posso vedere.
Shafik Yaghmour,

Sì, la promozione è la prima cosa che accadrà in entrambi i modi.
chris,

63

I valori booleani sono soggetti alle solite promozioni di numeri interi, con falsedefinite come 0e truedefinite come 1. Ciò rende ben definiti tutti i confronti.


2
... e gli operatori relazionali sono specificati per eseguire le solite conversioni aritmetiche (che includono promozioni intere) su operandi di tipo aritmetico o di enumerazione.
TC

5
Mi piace che questa risposta sia più breve di quella di Shafik, ma penso che il punto chiave che falseè definito come 0ed trueè definito come 1 nello standard (piuttosto che semplicemente dalla pratica comune) abbia bisogno di prove per sostenerlo.
KRyan

@KRyan cosa, non crederai alla mia parola? :) Prima che esistesse un booltipo, prima ancora del C ++, il risultato di un'operazione booleana veniva definito come 0falso e 1vero. Non sarei sorpreso se lo trovassi in K + R.
Mark Ransom,

1
@KRyan Non posso tornare indietro fino a K + R, ma ho estratto la mia copia dello standard ANSI C del 1990. La sezione 6.3.8 dice "Ciascuno degli operatori <(minore di), >(maggiore di), <=(minore o uguale a) e >=(maggiore o uguale a) restituisce 1 se la relazione specificata è vera e 0 se è false. Il risultato ha tipo int. "
Mark Ransom,

1
Il problema più grande di IIRC era che in K&R enum bool { false = 0, true = 1}era legale ma non ne definiva uno operator<.
Salterio

22

Secondo lo standard C ++ (5.9 Operatori relazionali)

2 Le normali conversioni aritmetiche vengono eseguite su operandi di tipo aritmetico o di enumerazione.

e

1 ... Il tipo di risultato è bool.

e (3.9.1 Tipi fondamentali)

6 I valori di tipo bool sono true o false.49 [Nota: non esistono tipi o valori bool firmati, non firmati, corti o lunghi. —End note] I valori di tipo bool partecipano a promozioni integrali (4.5).

e (4.5 promozioni integrali)

6 Un valore di tipo bool può essere convertito in un valore di tipo int, con false che diventa zero e true che diventa uno .

Quindi in tutti i tuoi esempi true viene convertito in int 1 e false viene convertito in int 0

Queste espressioni

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

sono del tutto equivalenti a

0 < 0
0 < 1
1 < 0
1 < 1

8

Booleano falseè equivalente a int 0, e booleano trueè equivalente a int 1. Quindi questo spiega perché l'espressione false < true=> 0 < 1è l'unica che ritorna true.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.