Visual C ++ Предупреждение C4800, почему он срабатывает только в операторах возврата? - PullRequest
3 голосов
/ 12 июля 2010

Я только что установил Windows SDK v7.1 (MSVC 10.0) и запускаю свой код на (почти) полном уровне предупреждения (W3, по умолчанию для qmake CONFIG += warn_on) и удивляюсь предупреждению C4800: 'type' : forcing value to bool 'true' or 'false' (performance warning)

В следующем коде stream - это std::istream, а token - это std::string.

// in some function returning bool
return (stream >> token) // triggers warning c4800:
                         // '(void *)': forcing value to bool 'true' or 'false' (performance warning)`
// somewhere else
if( stream >> token ) // does not trigger warning c4800

Что здесь происходит? Я даже не понимаю, почему предупреждение вызвано в первую очередь. Я думал, что первый бит кода уже вернул bool в любом случае.

Я понимаю, что это придирки, и предупреждение даже не должно существовать, но оно единственное в моем коде между MSVC /W3 и gcc -Wall -pedantic, поэтому я хотел бы знать:)

НЕБОЛЬШОЕ ОБНОВЛЕНИЕ : Я понимаю, что предупреждение предназначено для того, чтобы вы знали, что вы принимаете int-> bool-преобразование, но 1), почему бы вам даже использовать bool (== typedef int в основном) и 2) почему бы if(2) не преобразовать 2 в истинное или ложное, я думал, что в этом и заключается вся идея предиката, истинного или ложного.

Ответы [ 3 ]

5 голосов
/ 12 июля 2010

Что здесь происходит?Я даже не понимаю, почему предупреждение вызвано в первую очередь.Я думал, что первый бит кода уже все равно возвращает bool.

  1. Потоки имеют оператор неявного преобразования, который возвращает void*.(Это версия идиомы safe bool . Это сделано так, потому что есть меньше контекстов, в которых void* компилируется, чем bool, поэтому есть меньше контекстов, в которых неявное преобразование может вызвать нежелательное.) [1]

  2. Streams 'operator>>() возвращает ссылку на свой левый операнд - поток.Вот так вы можете связать операции ввода: strm >> value1 >> value2 выполняется как ((strm >> value1) >> value2).

Теперь, когда вы говорите if( strm >> value ), strm >> value выполняется и поток возвращается.Чтобы поместить это в оператор if, выполняется неявное преобразование в void*, и этот указатель затем проверяется на NULL или нет.
Это ничем не отличается от if(ptr), if оператор implicit преобразует свое условие в bool, но компиляторы никогда не предупредят об этом, потому что условие, не являющееся bool, является настолько распространенным.

С return все по-другому.Если вы хотите вернуть определенный тип, обычно возвращаемое выражение должно быть этого типа.Предупреждение ВК довольно раздражает, и для меня в 99 из 100 раз это было излишним.Но оставшийся 1% (никогда не беспокоился о производительности, кстати, я думаю, что это глупо в отношении предупреждения) заставил меня порадоваться, что предупреждение есть.

Обходной путь для этого предупреждения:

return 0 != <expression>

, где <expression> - это то, что, по вашему мнению, должно рассматриваться как логическое значение.

[1] ISTR Stroustrup пишет где-то, что operator bool() будет молча компилироваться, если вы испортите операторы: ostrm >> 5; (обратите внимание, >> вместо <<) будет компилироваться нормально, но молча делатьнеправильная вещь.(Он преобразует логическое значение в целое и смещает вправо 5 раз, а затем отбрасывает значение.)

3 голосов
/ 12 июля 2010

Разница между случаями, вероятно, заключается в том, что return должен генерировать возвращаемое значение, тогда как if не должен генерировать какое-либо значение, а просто ветвится. Очевидно, предупреждение о том, что должен быть создан новый объект данных, поэтому он вызывается return, но не if.

0 голосов
/ 12 июля 2010

Если условия оцениваются как ноль или не ноль, не преобразуются в логические значения.

, т.е. если (1) не генерирует предупреждение, потому что 1 не ноль.if (true) не генерирует предупреждение, потому что true оценивается как ненулевое.

Таким образом, целые числа, указатели, логические значения все преобразуются в «ноль или ненулевое значение», а не в логические значения.

Но когда вы пытаетесь вернуть целочисленное значение из функции с логическим возвратом, она должна предположить, что вы хотите имитировать это поведение.Вот почему это означает: «Я предполагаю, что вы хотите привести« ненулевое значение к истинному и нулевое к ложному », и вы получите предупреждение.

...