2014-10-01 31 views
149

Czy specyfikacji C++ określić:Czy operacja "false <true" jest dobrze zdefiniowana?

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

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

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

Na mojej konfiguracji (CentOS 7, gcc 4.8.2), kod poniżej wypluwa, czego można oczekiwać (biorąc pod uwagę historię C w reprezentacji jako fałszywe i prawdziwe jak 0: 1):

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

Chociaż jestem całkiem pewny, że większość (wszystkich?) Kompilatorów da takie same wyniki, czy jest to zgodne ze specyfikacją C++? Czy jest to zaciemnianie, ale kompilator zgodny ze specyfikacją może zdecydować, że prawda jest mniejsza od fałszywej?

#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; 
} 
+0

g ++ - 4.9.0 i clang ++ - 3.5.0 na Linuksie uważają, że to nic nadzwyczajnego: http://coliru.stacked-crooked.com/a/2174ebc466d0c445 – Deduplicator

+6

@Ulterior Istnieją ważne zastosowania. Takie jak użycie 'std :: min' na' std :: vector 'jako' && '. – Angew

+19

@Jeśli znajdziesz dobre pytanie, które nie zostało jeszcze zadane po tylu latach StackOverflow, * zasługujesz na * kilka punktów. To nie trolling. –

Odpowiedz

201

TL, DR:

operacje są dobrze zdefiniowane zgodnie z projektem normy C++.

Szczegóły

Widzimy, że przechodząc do sekcji draft C++ standard5.9operatory relacyjne który mówi (podkr przyszłości):

W argumenty mają arytmetyki , wyliczenie lub wskaźnik wpisz lub wpisz std :: nullptr_t. Operatory < (mniej niż),> (większe niż), < = (mniejsze niż lub równe) i> = (większe lub równe) wszystkie dają fałsz lub true. Typ wyniku jest bool

i bools są arithematic ów 3.9.1 podstawowych typów

Rodzaje bool, char, char16_t, char32_t, wchar_t i podpisane i niepodpisane typów całkowitych są łącznie nazywanymi typami całkowymi.

i

Integral i pływające typy są zbiorczo nazywane arytmetyka typy.

i true i false są boolean literały z 2.14.6 logiczne literałów:

boolean-literal: 
    false 
    true 

Wracając do sekcji 5.9 zobaczyć mechanikę relacyjnych operatorów dalej, to mówi:

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

się zwykłe arytmetyczne konwersje są ujęte w sekcji 5 który mówi:

W przeciwnym razie, integralny promocje (4.5) powinny być wykonywane na obu operandów

oraz sekcja 4.5 mówi :

A prvalue typu bool może zostać przekonwertowane na prvalue typu int, z false staje się zero i prawdziwe staje się jednym.

a więc wyrażenia:

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

wykorzystujące te zasady stały się:

0 < 0 
0 < 1 
1 < 0 
1 < 1 
+6

Przyjemnie, to jest tak jednoznaczne, jak każda możliwa odpowiedź, a jednocześnie łatwe do odczytania. Nit: Myślę, że pogrubiłeś zły "typ": "Operandy ** muszą mieć arytmetykę **, wyliczenie lub wskaźnik ** typ ** lub typ std :: nullptr_t." Dodanie nawiasów dla jasności daje (typ arytmetyczny, wyliczeniowy lub wskaźnikowy) lub (typ std :: nullptr_t). – hvd

+0

@ hvd dobry połów, naprawiony! –

+0

Nie zmienia to twojej odpowiedzi, ale N3485 [over.built]/12: * Dla każdej pary promowanych typów arytmetycznych L i R istnieją kandydujące funkcje operatorskie postaci * ... * operator bool <(L, R); * - Czy argumenty nie są promowane, zanim zasady, które cytujesz, mają zastosowanie? – chris

63

wartości logiczne podlegają zwykle promocji całkowitą z false zdefiniowany jako 0 i true zdefiniowany jako 1. To sprawia, że ​​wszystkie porównania są dobrze zdefiniowane.

+2

... i operatory relacyjne są określone, aby wykonywać typowe konwersje arytmetyczne (które obejmują liczby całkowite) na operandach arytmetycznych lub typach wyliczeniowych. –

+5

Podoba mi się, że ta odpowiedź jest krótsza niż Shafik, ale myślę, że kluczowy punkt, w którym "fałsz" jest zdefiniowany jako "0" i "prawdziwy" jest zdefiniowany jako "1" * w standardzie * (zamiast zwykłej praktyki) potrzebuje dowodów, aby go poprzeć. – KRyan

+0

@ Kiran, co, nie masz zamiaru wierzyć mi na słowo?:) Zanim pojawił się typ 'bool', zanim istniało nawet C++, wynik operacji boolowskiej został zdefiniowany jako' 0' dla false i '1' dla true. Nie zdziwiłbym się, gdyby można go było znaleźć w K + R. –

22

Według C++ Standard (5.9 operatory relacyjne)

2 zwykłej arytmetyki konwersje są wykonywane na operandach z arytmetem ic lub typ wyliczeniowy.

i

1 ... typ wyniku jest bool.

i (3.9.1 Podstawowe typy)

6 wartości typu bool są albo prawdziwe, albo false.49 [Uwaga: Brak podpisane, typy niepodpisane, krótkie lub długie lub bool wartości. -end note] Wartości typu bool uczestniczą w integralnych promocjach (4.5).

i (4,5 całkowe promocjach)

6a prvalue typu bool można przekształcić do prvalue typu int z fałszywie się zerem i prawdziwe staje się jedną.

Więc we wszystkich przykładach prawdziwych jest konwertowany do int 1 i fałszywa jest konwertowany do int 0

tych wyrażeń

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

są całkowicie równoważne

0 < 0 
0 < 1 
1 < 0 
1 < 1 
7

Boolean false jest równoważne int 0, a boolean true jest równoznaczne z adresem int 1. Wyjaśnia to, dlaczego wyrażenie false < true =>0 < 1 jest jedynym, które zwraca true.