Правильно ли определена операция «ложь <истина»?

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 ++? Или же запутанный, но совместимый со спецификацией компилятор позволил решить, что true меньше, чем 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;
}
Duncan
источник
6
@Ulterior Есть допустимые варианты использования. Такие как использование std::minна std::vector<bool>как &&.
Angew больше не гордится SO
19
@ Внешне, если вы можете найти хороший вопрос, который еще не задавался после всех этих лет StackOverflow, вы заслуживаете некоторых баллов. Это не троллинг.
Марк Рэнсом
35
@Ulterior Мотивация для запроса является подлинной: я довольно плохо знаком с C ++ (из C) и хочу хранить некоторые объекты в std :: set <>. Моя реализация оператора <моего объекта в первую очередь основана на логическом свойстве объекта, за которым следуют другие вторичные идентифицирующие свойства. Итерируя по множеству, я хочу быть уверенным, что «ложные» объекты идут первыми. В то время как это работает для меня здесь и сейчас, я ищу заверения, что он гарантированно будет работать на разных платформах (включая встроенные) без необходимости прибегать к использованию (a? 1: 0) или подобному, в моем объекте < оператор.
Дункан
26
Тревожным следствием является то, что p <= qозначает, p implies qкогда pи qимеют тип bool!
Теодор Норвелл
4
@ Technophile Предположительно, что беспокоит то, что <=может быть случайно прочитано в виде левой стрелки, и что правая стрелка «только если» (т. Е. «[Материально] подразумевает») иногда набирается или неофициально пишется аналогично =>(т. Е. С удвоенным стержнем, напоминающим =) , Левая стрелка даже иногда читается как «если», хотя я считаю, что это гораздо реже, чем использование правой стрелки для «только если».
Элия ​​Каган

Ответы:

207

TL; DR:

Операции четко определены в соответствии с проектом стандарта C ++.

подробности

Мы можем увидеть это, перейдя к черновому стандартному разделу C ++ « 5.9 Реляционные операторы», в котором говорится ( выделение мое в дальнейшем )

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

и bools являются арифметическими типами из 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говорит:

Prvalue типа bool может быть преобразовано в prvalue типа int, где false становится равным нулю, а true становится единым.

и так выражения:

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

с помощью этих правил становятся:

0 < 0
0 < 1
1 < 0
1 < 1
Шафик Ягмур
источник
6
Хорошо, это примерно так же ясно, как любой ответ, хотя все еще легко читается. Внимание: я думаю, что вы набрали неправильный «тип»: « Операнды должны иметь арифметический тип , тип перечисления или указатель или тип std :: nullptr_t.» Добавление скобок для ясности дает ((арифметическое, перечисление или указатель) тип) или (тип std :: nullptr_t).
Не то, чтобы это изменило ваш ответ, но N3485 [over.built] / 12: для каждой пары повышенных арифметических типов L и R существуют операторные функции-кандидаты вида ... оператор bool <(L, R); - Разве аргументы не приводятся до того, как приведенные вами правила даже применяются?
Крис
@ Крис Я не очень знаком с этим разделом, поэтому мне нужно подумать об этом, но я не думаю, что ответ меняется с того, что я вижу.
Шафик Ягмур
Да, продвижение - это первое, что должно произойти в любом случае.
Крис
63

Булевы значения подчиняются обычным целочисленным повышениям, которые falseопределены как 0и trueопределены как 1. Это делает все сравнения хорошо определенными.

Марк Рэнсом
источник
2
... и реляционные операторы определены для выполнения обычных арифметических преобразований (которые включают в себя целочисленные преобразования) над операндами арифметического или перечислимого типа.
ТЦ
5
Мне нравится, что этот ответ короче, чем ответ Шафика, но я думаю, что ключевой момент, который falseопределен как 0и trueопределен как 1 в стандарте (а не только в обычной практике), нуждается в доказательствах, подтверждающих его.
KRyan
@KRyan что, ты не собираешься поверить мне на слово? :) До того, как появился boolтип, до того, как появился C ++, результат логической операции был определен как 0для false и 1для true. Я не удивлюсь, если вы найдете это в K + R.
Марк Рэнсом
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 имеют значение true или false.49 [Примечание. Типы или значения типа bool со знаком, без знака, с коротким или длинным типом отсутствуют. - примечание] Значения типа bool участвуют в интегральных повышениях (4.5).

и (4.5 Интегральные акции)

6 Значение типа bool можно преобразовать в значение типа int, где значение false становится равным нулю, а значение true становится единым .

Таким образом, во всех ваших примерах 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.

Blindstealer
источник