2016-11-27 7 views
3

Возьмите эту игрушку код:неявного преобразования потока в BOOL

#include <iostream> 
#include <fstream> 

int main() { 

    std::ifstream is; 
    // perform read 
    // ... 
    if (!is) // works 
     std::cout << "fail"; 
    if(is == false) // error C2678 
     std::cout << "fail"; 

    return 0; 
} 

Вы получили бы следующий нелогичные результаты: if(!is) компилирует и if(is==false) дает

ошибка C2678: бинарное «= = ': оператор не найден, который принимает левый операнд типа' std :: ifstream '(или нет приемлемого преобразования)

(для VS2015 - аналогичные ошибки в gcc и clang).

Стандарт говорит (согласно this answer):

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

  • передавая значение функции, которая принимает аргумент типа BOOL;

  • с использованием оператора == для сравнения с ложным или истинным;

  • возвращение значения из функции с возвратным типом bool;

  • инициализация элементов типа bool посредством инициализации агрегата;

  • Инициализация const bool &, который будет привязан к временному.

Насколько я могу сказать if(is==false) явно требуется потерпеть неудачу, но как же if(!is) не? Не квалифицируется ли это как «неявное логическое преобразование»?

Было ли это преобразование в bool преднамеренно опущено из случаев, перечисленных в стандарте? Возможно, это непреднамеренное упущение?


Edit: Этот код не только так:

int main() { 

    std::ifstream is; 
    // perform read 
    // ... 
    if (is) // works 
     std::cout << "success"; 
    if(is == true) // error C2678 
     std::cout << "success"; 

    return 0; 
} 

А вот присутствие оператора() не имеет значения.

ответ

6

std::ifstream «s унаследовали operator bool является marked explicit:

explicit operator bool() const; (2) (так как C++ 11)

Что это означает, что не существует не неявного преобразования в Bool , т.е. все эти выражения терпят неудачу:

bool result = is; // fails 
bool b = is == true; // fails 
if (is == false); // fails 
while (is == false); // fails 

Если вы задаетесь вопросом, почему if (is) и аналогичные утверждения компилируются, то есть существуют специальные правила для if, while и т. П. Для конверсий: ключевое слово explicit игнорируется!

if (is);      // ok 
while (is)      // ok 
bool b = static_cast<bool>(is); // ok 

Обратите внимание, что последний случай компилируется, потому что вы явно желая логическое значение.

Технически !is будет работать нормально, как вы явно хотите логического значения, но std::ifstream имеет унаследовал operator!, так что оператор называется вместо стандартного operator!, который действует на BOOLS:

if (!is);  // ok 
bool b = !is; // ok 
+2

Он может [потенциально работать] (http://coliru.stacked-crooked.com/a/b5f1f0d91368afc3) без явного 'operator!' – StoryTeller

+0

Я также думаю, что он может работать так же, как 'is && true' делает –

+0

@StoryTeller Oh круто, не знал этого. Спасибо :) – Rakete1111

4

!is работает, потому что std::basic_ios, один из базовых классов для потоков, имеет operator!().

Так что это вовсе не преобразование, это вызов is.operator!().

+0

You» правильно, но это не основная причина. Я отредактировал вопрос, чтобы его отразить: 'if (is)' преуспевает как 'if (! Is)' –

+0

Да, потому что 'std :: basic_ios' также имеет' operator bool() ', который дополняет' operator !() '. –

+0

Оператор помечен как «явный», который является источником путаницы. Оказывается, явный квалификатор игнорируется в этом контексте –

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