Чи чітко визначена операція "хибність <правда"?


153

Чи визначає специфікація C ++:

  1. існування оператора "менше ніж" для булевих параметрів, і якщо так,
  2. результат 4 перестановок параметра?

Іншими словами, чи визначені специфікацією результати наступних операцій?

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

У моїй установці (Centos 7, gcc 4.8.2) наведений нижче код виказує те, що я очікував (з огляду на історію C, що представляє false як 0 та true як 1):

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

Хоча я впевнений, що більшість (усіх?) Компіляторів дадуть однаковий результат, чи це законодавство визначається специфікацією C ++? Або компульсивний компілятор, який відповідає специфікаціям, може вирішити, що правда менша за помилкову?

#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 Є дійсне використання. Такі як використання std::minна std::vector<bool>як &&.
Ендже вже не пишається ТАК

19
@Ulterior, якщо ви зможете розібратися з хорошим питанням, яке ще не задавались після всіх цих років StackOverflow, ви заслуговуєте на деякі моменти. Це не тролінг.
Марк Рансом

35
@Ulterior Мотивація запиту справжня: я досить новачок у C ++ (походить від C) і хочу зберігати деякі об’єкти в std :: set <>. Моя реалізація <оператора мого об'єкта ґрунтується насамперед на булевій властивості об'єкта, а потім на інших вторинних властивостях ідентифікації. Перебираючи набір, я хочу бути впевненим, що "помилкові" об'єкти виходять першими. Хоча це працює для мене тут і зараз, я шукаю запевнення, що це гарантовано працювати на платформах (включаючи вбудовані), без необхідності вдаватися до використання (a? 1: 0) або подібного в моєму об'єкті < оператор.
duncan

26
Тривожним наслідком є ​​те, що p <= qозначає, p implies qколи pі qє тип булінгу!
Теодор Норвелл

4
@Technophile Імовірно, що тривожне, це те, що <=може бути ненавмисно прочитане як ліворуч, і що "тільки якщо" (тобто "[матеріально] має на увазі") "правда іноді набирається або неофіційно пишеться аналогічно =>(тобто, з подвоєним валом, що нагадує =) . Ліворука навіть іноді читається як "якщо", хоча я вважаю, що це набагато рідше, ніж використання прямокутниці для "лише якщо".
Елія Каган

Відповіді:


207

TL; DR:

Операції чітко визначені відповідно до проекту стандарту C ++.

Деталі

Це ми можемо побачити, перейшовши на проект стандартного розділу C ++ 5.9 Реляційні оператори, який говорить ( акцент минає вперед ):

У операнди повинні мати арифметичний , перерахування, або покажчик типу , або типу зЬй :: nullptr_t. Оператори <(менше, ніж),> (більше, ніж), <= (менше або дорівнюють) і> = (більше або дорівнюють) всі дають помилкові чи істинні. Тип результату - bool

і булі - це арифметичні типи від 3.9.1 Основні типи

Типи bool , char, char16_t, char32_t, wchar_t, а також підписані та непідписані цілі цілі типи називаються цілісними типами.

і

Інтегральні та плаваючі типи спільно називають арифметичними типами.

і trueі falseє булеві літерали з 2.14.6булевих литералов:

boolean-literal:
    false
    true

Повертаючись до розділу, 5.9щоб побачити механіку реляційних операторів далі, він говорить:

Звичайні арифметичні перетворення виконуються на операндах арифметичного чи перелічувального типу.

що звичайні арифметичні перетворення розглядаються в розділі , 5де йдеться:

В іншому випадку інтегральні промоції (4.5) повинні виконуватися на обох операндах

і розділ 4.5говорить:

Двозначне bool типу може бути перетворене в первісне значення типу int, при цьому помилкове стає нульовим, а істинне стає єдиним.

і так вирази:

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

з використанням цих правил стають:

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

6
Приємно, це настільки ж явно, як і будь-яка відповідь, але все ще легко читається. Nit: Я думаю, що ви закреслили неправильний "type": " Операнди повинні мати арифметику , перерахування чи тип вказівника , або тип std :: nullptr_t." Додавання круглих дужок для ясності надає ((арифметичні, нумераційні чи вказівні) типи) або (тип std :: nullptr_t).

Не те, що це змінює вашу відповідь, але N3485 [over.built] / 12: Для кожної пари рекламованих арифметичних типів L і R існують функції кандидат-оператора форми ... оператор bool <(L, R); - Чи не висуваються аргументи до того, як цитуються правила, які ви цитуєте?
chris

@chris Я не надто знайомий з цим розділом, тому мені доведеться подумати над цим, але я не думаю, що відповідь змінюється від того, що я бачу.
Шафік Ягмур

Так, просування - це перше, що відбувається в будь-якому випадку.
chris

63

Булеві значення залежать від звичайних цілих акцій, falseвизначених як 0і trueвизначених як 1. Це робить усі порівняння чітко визначеними.


2
... і реляційні оператори задаються для виконання звичайних арифметичних перетворень (що включає цілі промоції) на операндах арифметичного або перелічувального типу.
ТК

5
Мені подобається, що ця відповідь є коротшою, ніж у Шафіка, але я вважаю, що ключовий момент, який falseвизначається як 0і trueвизначений як 1 у стандарті (а не просто за звичайною практикою), потребує доказів, щоб підтвердити це.
KRyan

@KRyan що, ти не збираєшся приймати за це моє слово? :) Перш ніж був boolтип, перш ніж навіть був C ++, результат булевої операції визначався як 0для false, так і 1для true. Я не був би здивований, якщо ви знайдете його в K + R.
Марк Викуп 11

1
@KRyan Я не можу повернутися далеко до K + R, але я розкопав свою копію стандарту ANSI C 1990 року. У розділі 6.3.8 сказано: "Кожен з операторів <(менше), >(більший), <=(менший або рівний) та >=(більший або рівний) повинен отримати 1, якщо вказане відношення є істинним, і 0, якщо воно false. Результат має тип int. "
Марк Рансом

1
Найбільшою проблемою IIRC було те, що в K&R enum bool { false = 0, true = 1}було законним, але не визначало operator<.
MSalters

22

Відповідно до стандарту C ++ (5,9 реляційних операторів)

2 Звичайні арифметичні перетворення виконуються на операндах арифметичного чи перелічувального типу.

і

1 ... Тип результату - bool.

та (3.9.1 Основні типи)

6 Значення типу bool є істинними, або хибними.49 [Примітка: Немає підписаних, непідписаних, коротких чи довгих типів або значень bool. —Закінчити примітку] Значення типу bool беруть участь у цілісних акціях (4.5).

та (4.5 інтегральних акцій)

6 Перша величина bool типу може бути перетворена в первісну величину типу int, при цьому помилка стає нульовою, а істина стає єдиною .

Отже, у всіх ваших прикладах true перетворюється на int 1, а false - на int 0

Ці вирази

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

цілком еквівалентні

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

8

Булева falseеквівалентна int 0, а булева trueеквівалентна int 1. Отже, це пояснює, чому вираз false < true=> 0 < 1є єдиним, що повертається true.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.