2013-08-29 5 views
8

Заголовок <windows.h> поставляется со своим собственным номером BOOL. Peeking при реализации, кажется FALSE - это просто макрос для 0, а TRUE - это всего лишь макрос для 1, но я не уверен, что это указано.Как я идиоматически конвертировать BOOL в bool?

Что такое идиоматический способ преобразования BOOL в bool? Я могу представить себе множество возможных способов:

bool a = static_cast<bool>(x); 

bool b = x ? true : false; 

bool c = (x == TRUE); 

bool d = (x != FALSE); 

bool e = !!x; 

// ... 
+0

Что вы подразумеваете под «идиоматическим»? –

+0

'bool c = (x = FALSE)'? :) – Inspired

+0

Это, вероятно, неприемлемо для SO, потому что это сводится к личным вкусам, я считаю. – lpapp

ответ

6

Там нет необходимости в какой-либо явного преобразования:

BOOL x = some_value; 
bool b = x; 

неявное преобразование числового типа в bool дает false для значения 0 и true для любое ненулевое значение.

Кстати, вы сказали нам, как <windows.h> определяет FALSE и TRUE. Как он определяет BOOL? (Из вашего комментария, это typedef int BOOL;)

Но некоторые компиляторы могут предупреждать об этом неявном преобразовании, даже если это совершенно правильный код. Компиляторы могут предупреждать о чем угодно, включая уродливый шрифт, который вы использовали для написания кода. г ++, например, не жалуется на преобразования, даже с:

g++ -std=c++11 -pedantic -Wall -Wextra ... 

Но согласно this online Visual C++ compiler, VC++ действительно производит предупреждение:

warning C4800: 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) 

Даже с static_cast, она по-прежнему производит предупреждение.

Вы можете избежать предупреждения, используя !!x или x ? true : false. Но я не уверен, что лечение лучше, чем болезнь.

Простой и правильный способ сделать это - просто назначить значение и полагаться на неявное преобразование, чтобы делать правильную вещь (она будет).

Если у вас есть дополнительные требования, чтобы избежать предупреждений компилятора, это становится скорее вопросом о Visual C++, а не о языке C++. Также может быть какой-то способ заблокировать определенные предупреждения без изменения источника - хотя это рискует потерять те же самые предупреждения, когда они действительно имеют смысл. В комментарии Дитер Люкинг предлагает:

#pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' (performance warning) 

но похоже, что он по-прежнему требует изменения источника. Возможно, есть что-то подобное, чего нет. более

одно: поскольку BOOL действительно типа int, это предложенное решение:

bool c = (x == TRUE); 

не эквивалентен другим. Любое ненулевое значение int считается истинным, но только значение 1 равно , равное - TRUE.Вышеуказанное установит c на false, если x == 2, например - тогда как if (x) все равно будет считать это истинным условием. Никогда не сравнивайте логические значения для равенства с true или TRUE. (Сравнивая их false или FALSE безопаснее, но до сих пор нет необходимости, т. Е то, что оператор ! для)

Все это предполагает, что если у вас есть значение типа BOOL, вы только заботитесь ли это falsish или truthy (ноль или ненулевое значение). К сожалению, это не всегда так. Как указывает Ben Voight's answer, API Microsoft включает в себя как минимум одну функцию, GetMessage, которая возвращает результат BOOL, который равен , а не - простое булево значение. В таком ужасном случае преобразование с BOOL в bool не подходит, если вам нужно различать множество ненулевых значений.

В конечном счете, я обвиняю Microsoft в определении типа BOOL для языка, который уже имеет совершенно хорошо встроенный тип bool. На самом деле это не совсем справедливо; он используется в API, которые должны быть доступны как с C, так и с C++. Определение Microsoft BOOL, вероятно, восходит к их реализации C, где это имеет смысл - по крайней мере до C99, который Microsoft по-прежнему не поддерживает. (Я не знаю, даже если это произойдет, _Bool, есть ли поддержка C компилятор от Microsoft _Bool некоторые смысловые отличия от int, и изменить определение BOOL может нарушить код -.. В частности, код, использующий GetMessage)

+2

Это дает мне предупреждение о компиляторе. В противном случае я бы не спросил :) – fredoverflow

+0

'typedef int BOOL; ' – fredoverflow

+1

@FredOverflow: Какое предупреждение? (И почему вы не упомянули об этом и не указали предупреждение в своем первоначальном вопросе?) Компиляторы могут предупреждать о чем угодно; gcc, например, * не предупреждает о неявном преобразовании из 'int' в 'bool'. И, пожалуйста, обновите свой вопрос, чтобы показать, что typedef. –

0

Это трудно сказать, как бы win32 программист это сделать, но ИМХО это должно быть сделано:

bool c = (X == TRUE); 

или

bool d = (x != FALSE); 

Я думаю, что это плохо р ractice для передачи на макрос (или любой другой предопределенный материал)
постоянство.

Однажды ИСТИНА может стать 0 и FALSE 1;)

+1

Этот день, вроде: ['VARIANT_BOOL'] (http://msdn.microsoft.com/en-us/library/cc237864.aspx) может быть назначен' VARIANT_FALSE' и 'VARIANT_TRUE', причем последний определяется как '(короткий) -1', другими словами 0xFFFF. В Windows я предлагаю всегда использовать 'bool d = (x! = FALSE);'. Вы не можете ожидать, что все в вашей команде будут знать, как правильно конвертировать из 'VARIANT_BOOL' в' BOOL'. – IInspectable

0

Там нет безопасного способа сделать это, потому что Win32 BOOL имеет more than two values.

+0

Предполагается, что вам нужно сохранить эти значения. Если это используется здраво, вам все равно, насколько это правдиво или фальшиво. –

+0

@Keith: Это верно для многих API, но тот, с которым я связан, возвращает значения из трех классов эквивалентности. –

+0

Это глупый, глупый, глупый API. (Изменение типа возврата с 'BOOL' на' int' решит эту проблему и не имеет никакого значения для API.) –

1

Я использую макрос:

#define _bool(b) (!!(b)) 

ИМО, делает мой код более читаемым.

EDITED: комментатор оспаривает мое использование подчеркивания в имени макроса. Чтобы решить эту проблему, вот новая версия, которая по-прежнему носит общий характер и все еще использует одно и то же имя _bool, но соответствует, согласно this.

namespace MyBool 
{ 
    template<typename T> inline bool _bool(const T b) 
    { 
     return !!b; 
    } 
} 

using namespace MyBool; 
+0

Имена, которые начинаются с символа подчеркивания в глобальном пространстве имен, [зарезервированы] (http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-ac-identifier) , – IInspectable

+0

Не проблема для меня. Этот макрос используется только моим собственным кодом и расширяется с помощью препроцессора, поэтому компилятор и пространства имен ничего не знают об этом. Во всяком случае, можно использовать '__bool'. – avo

+0

Имя, содержащее двойное подчеркивание, зарезервировано ** везде **. Это не имеет никакого отношения к ** вашему ** коду. Существуют правила для предотвращения конфликтов имен с реализацией C++. Конечно, вы не хотите, чтобы стандартный заголовок библиотеки включал защиту от конфликта с кодом, использующим его. Безопасной альтернативой было бы следующее: 'bool bool_ (const BOOL b) {return !! b;}' – IInspectable

0

Это вопрос мнения, но я считаю, что существуют объективные аргументы в пользу различных вариантов.

Лучший выбор:

bool d = (x != FALSE); 

Это делает намерение очень ясно читателю, не полагаться на неявные преобразования, и становится ясно, что там больше происходит, чем простое присваивание.

Второй лучший выбор:

bool b = x ? true : false; 

Но, к случайному читателю, что может показаться, как тавтология.

Я стараюсь избегать неявных преобразований в назначениях, потому что получение неправильного преобразования является удивительным источником ошибок. Даже когда I знает, неявное преобразование будет правильно, я стараюсь делать это явно, что может быть полезно для кого-то, читающего код в будущем. Быть явным также позволяет включить предупреждения о конверсиях, чтобы вы могли поймать другие неявные преобразования, которые вы не знали о (ab) использовании.

Все альтернативы имеют более серьезные недостатки.

bool a = static_cast<bool>(x); 

Это как забивание квадратного штифта в круглое отверстие. Элегантно написать выражение, которое, естественно, возвращает правильный тип.

bool c = (x == TRUE); 

Это вообще плохая идея, чтобы сравнить TRUE, так как другие ненулевые значения будут конвертировать в ложь, что почти наверняка ошибка.

bool e = !!x; 

Слишком умный по сравнению с альтернативами, которые точно выражают то, что вы имеете в виду. (Я виновен в том, сделал это в прошлом.)

bool f = x; 

Производительность предупреждения MSVC++ излучает на чисто неявное преобразование кажется справедливым. Компилятор должен генерировать дополнительный код для преобразования int в bool. Непосредственное задание дает мало информации об этой дополнительной работе. Если он находится в плотной петле, вам все равно. (Конечно, предупреждение об исполнении опциона static_cast кажется вопиющим, но мы уже исключили, что, как менее элегантно.)

d и b выражения четко выразить намерение и сделать это очевидным, что там больше происходит здесь, чем прямое назначение.

Смежные вопросы