Czy operacja „fałsz <prawda” jest dobrze zdefiniowana?

153

Czy specyfikacja C ++ definiuje:

  1. istnienie operatora „mniejsze niż” dla parametrów logicznych, a jeśli tak,
  2. wynik permutacji 4 parametrów?

Innymi słowy, czy wyniki następujących operacji są zdefiniowane w specyfikacji?

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

W mojej konfiguracji (Centos 7, gcc 4.8.2) poniższy kod wypluwa to, czego bym się spodziewał (biorąc pod uwagę historię C reprezentowania fałszu jako 0 i prawdy jako 1):

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

Chociaż jestem prawie pewien, że większość (wszystkich?) Kompilatorów da takie same dane wyjściowe, czy jest to uregulowane w specyfikacji C ++? A może zaciemniający, ale zgodny ze specyfikacją kompilator może zdecydować, że prawda jest mniejsza niż fałsz?

#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
źródło
6
@Ulterior Istnieją ważne zastosowania. Takich jak używanie std::minna std::vector<bool>co &&.
Angew nie jest już dumny z
19
@Ulterior, jeśli potrafisz wymyślić dobre pytanie, które nie zostało jeszcze zadane po tych wszystkich latach StackOverflow, zasługujesz na kilka punktów. To nie jest trollowanie.
Mark Ransom
35
@Ulterior Motywacja do zadawania pytań jest prawdziwa: jestem całkiem nowy w C ++ (pochodzę z C) i chcę przechowywać niektóre obiekty w std :: set <>. Moja implementacja operatora <mojego obiektu opiera się głównie na właściwości logicznej obiektu, po której następują inne drugorzędne właściwości identyfikujące. Podczas iteracji po zestawie chcę mieć pewność, że „fałszywe” obiekty pojawią się jako pierwsze. Chociaż to działa dla mnie tu i teraz, szukam pewności, że na pewno będzie działać na różnych platformach (w tym osadzonych) bez konieczności niepotrzebnego uciekania się do użycia (a? 1: 0) lub podobnego w < operator.
duncan
26
Niepokojącą konsekwencją jest to, że p <= qśrodki p implies qkiedy pi qsą typu BOOL!
Theodore Norvell
4
@Technophile Przypuszczalnie niepokojące jest to, że <=może być przypadkowo odczytane jako strzałka w lewo i że „tylko jeśli” (tj. „[Materialnie] sugeruje”) strzałka w prawo jest czasami składana lub nieformalnie zapisywana podobnie do =>(tj. Z podwójnym trzonem przypominającym =) . Czasami nawet czyta się lewą strzałkę jako „jeśli”, chociaż uważam, że jest to znacznie mniej powszechne niż użycie prawej strzałki dla określenia „tylko jeśli”.
Eliah Kagan

Odpowiedzi:

207

TL; DR:

Operacje są dobrze zdefiniowane zgodnie z projektem standardu C ++.

Detale

Widzimy to przechodząc do szkicu standardowej sekcji C ++ 5.9 Operatory relacyjne, która mówi ( podkreślenie moje w przód ):

Te argumenty mają arytmetyczny , wyliczenie, czy wskaźnik rodzaj lub typ std :: nullptr_t. Wszystkie operatory <(mniejsze niż),> (większe niż), <= (mniejsze lub równe) i> = (większe lub równe) dają wartość false lub true. Typ wyniku to bool

a bools są typami aritematycznymi z 3.9.1 Typy podstawowe

Typy bool , char, char16_t, char32_t, wchar_t oraz typy całkowite ze znakiem i bez znaku są łącznie nazywane typami całkowitymi.

i

Typy całkowe i zmiennoprzecinkowe są zbiorczo nazywane typami arytmetycznymi.

i truei falsesą logiczne literałów z 2.14.6logicznych literałów:

boolean-literal:
    false
    true

Wracając do sekcji, 5.9aby dokładniej przyjrzeć się mechanice operatorów relacyjnych, jest napisane:

Zwykłe konwersje arytmetyczne są wykonywane na operandach typu arytmetycznego lub wyliczeniowego.

to zwykłe konwersje arytmetyczne są objęte w części 5, która mówi:

W przeciwnym razie promocje całkowe (4.5) będą wykonywane na obu operandach

a sekcja 4.5mówi:

Wartość pr typu bool może zostać przekonwertowana na prwartość typu int, gdzie false staje się zerem, a true staje się jedynką.

a więc wyrażenia:

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

korzystając z tych reguł należy:

0 < 0
0 < 1
1 < 0
1 < 1
Shafik Yaghmour
źródło
6
Fajnie, to mniej więcej tak wyraźne, jak mogłaby być każda odpowiedź, a jednocześnie łatwe do odczytania. Nit: Myślę, że pogrubiłeś niewłaściwy "typ": " Operandy powinny mieć typ arytmetyczny , wyliczeniowy lub wskaźnikowy lub typ std :: nullptr_t." Dodanie nawiasów w celu zwiększenia przejrzystości daje ((arytmetyczny, wyliczeniowy lub wskaźnikowy) typ) lub (typ std :: nullptr_t).
Nie żeby zmieniało to twoją odpowiedź, ale N3485 [over.built] / 12: Dla każdej pary promowanych typów arytmetycznych L i R istnieją kandydujące funkcje operatora w postaci ... operator bool <(L, R); - Czy argumenty promowane przed regułami, które przytaczasz, w ogóle nie mają zastosowania?
Chris
@chris Nie jestem zbyt zaznajomiony z tą sekcją, więc musiałbym się nad tym zastanowić, ale nie sądzę, aby odpowiedź różniła się od tego, co widzę.
Shafik Yaghmour
Tak, awans jest pierwszą rzeczą, jaka się wydarzyła.
chris
63

Wartości logiczne podlegają zwykłym promocjom na liczby całkowite, przy czym falsezdefiniowano jako 0i truezdefiniowano jako 1. To sprawia, że ​​wszystkie porównania są dobrze zdefiniowane.

Mark Okup
źródło
2
... i operatory relacyjne są określone do wykonywania zwykłych konwersji arytmetycznych (w tym promocji liczb całkowitych) na operandach typu arytmetycznego lub wyliczeniowego.
TC
5
Podoba mi się, że ta odpowiedź jest krótsza niż odpowiedź Shafika, ale myślę, że kluczowy punkt, który falsejest zdefiniowany 0i truezdefiniowany jako 1 standard (a nie tylko przez powszechną praktykę), wymaga dowodów na poparcie tego.
KRyan
@KRyan co, nie uwierzysz mi na słowo? :) Zanim istniał booltyp, zanim jeszcze istniał C ++, wynik operacji logicznej był definiowany jako 0fałsz i 1prawda. Nie zdziwiłbym się, gdybyś mógł go znaleźć w K + R.
Mark Ransom
1
@KRyan Nie mogę cofnąć się tak daleko, jak K + R, ale wykopałem swoją kopię normy ANSI C. z 1990 roku. Sekcja 6.3.8 mówi: „Każdy z operatorów <(mniejszy niż), >(większy niż), <=(mniejszy lub równy) i >=(większy lub równy) daje 1, jeśli określona relacja jest prawdziwa, i 0, jeśli jest fałsz. Wynik ma typ int. "
Mark Ransom
1
Największym problemem IIRC było to, że w K&R enum bool { false = 0, true = 1}było legalne, ale nie zdefiniowało operator<.
MSalters
22

Zgodnie ze standardem C ++ (5.9 Operatory relacyjne)

2 Zwykłe konwersje arytmetyczne są wykonywane na operandach typu arytmetycznego lub wyliczeniowego.

i

1 ... Typ wyniku to bool.

i (3.9.1 Podstawowe typy)

6 Wartości typu bool to prawda lub fałsz.49 [Uwaga: nie ma typów ani wartości typu bool ze znakiem, bez znaku, krótkich ani długich. —End note] Wartości typu bool uczestniczą w promocjach integralnych (4.5).

i (4.5 promocje integralne)

6 Wartość pr typu bool może zostać przekonwertowana na prwartość typu int, gdzie false staje się zerem, a true staje się jedynką .

Zatem we wszystkich twoich przykładach wartość true jest konwertowana na liczbę int 1, a fałsz na liczbę całkowitą 0

Te wyrażenia

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

są całkowicie równoważne z

0 < 0
0 < 1
1 < 0
1 < 1
Vlad z Moskwy
źródło
8

Boolean falsejest równoważny int 0, a boolean truejest równoważny int 1. To wyjaśnia, dlaczego wyrażenie false < true=> 0 < 1jest jedynym, które zwraca true.

Blindstealer
źródło