Как std:: cin возвращает bool и сам в одно и то же время?
Я читаю книгу на С++, в которой говорится, что если я использую оператор → , он возвращает объект в левой части оператора, поэтому в этом примере
std::cin >> value1;
код возвращает std::cin
.
Но если я это сделаю
while(std::cin >> value1)
Мой код будет в цикле до тех пор, пока не будет ошибка std::cin
, так что это должно означать, что оператор возвращает bool
, который является истинным, когда std::cin
не сбой, а false, когда std::cin
терпит неудачу.
Что это такое?
Ответы
Ответ 1
[...], так что это должно означать, что оператор возвращает bool [...]
Нет, он возвращает std::cin
(по ссылке). Причина, по которой работает while(std::cin >> value);
, состоит в том, что std::istream
(тип std::cin
) имеет оператор преобразования.
Оператор преобразования в принципе позволяет неявному (если он не помечен explicit
) классу быть преобразованным в заданный тип. В этом случае std::istream
определяет свой operator bool
для возврата, произошла ли ошибка (обычно failbit
);
[std::ios_base::operator bool()]
Возвращает true
, если поток не имеет ошибок и готов к операциям ввода-вывода. В частности, возвращает !fail()
.
explicit operator bool() const;
Обратите внимание, что хотя оператор explicit
(который не должен допускать неявные преобразования, такие как if (std::cin);
), квалификатор игнорируется при использовании в контексте, который требует bool
, например if
, while
и циклы for
. Это исключения, но не правила.
Вот пример:
if (std::cin >> value); //OK, a 'std::istream' can be converted into a 'bool', which
//therefore happens implicitly, without the need to cast it:
if (static_cast<bool>(std::cin >> value)); //Unnecessary
bool b = std::cin >> value; //Error!! 'operator bool' is marked explicit (see above), so
//we have to call it explicitly:
bool b = static_cast<bool>(std::cin >> value); //OK, 'operator bool' is called explicitly
Ответ 2
std::istream
(класс, который std::cin
является объектом) имеет следующую функцию-член:
explicit operator bool() const;
Он возвращает false, если объект находится в состоянии ошибки, и true в противном случае. Вот почему работает конструкция while(std::cin >> value1)
. Перед С++ 11 вместо этого была использована эта неявная функция:
operator void*() const;
Что вернуло нулевой указатель, если объект находился в состоянии ошибки, служащей той же цели.
Ответ 3
Операции с потоками возвращают ссылку на поток.
Итак, не bool
.
Вы можете вставить результат в условие if
по той же причине, что вы можете сделать это:
void* ptr = foo();
if (ptr) { /*...*/ }
И, если на то пошло, это:
int x = foo();
if (x) { /*...*/ }
Оба ptr
и x
здесь могут быть преобразованы в bool
для использования в условии. В случае std::cin
преобразование достигается с помощью operator bool()
в классе std::ostream
, который был явно (предназначен для каламбуров) для этой точной задачи.
Ответ 4
std::cin
имеет тип std::istream
(который является просто a typedef
std::basic_istream<char>
)
Если вы видите разные перегруженные operator>>
для basic_istream
, все они возвращают ссылку на basic_istream
. Итак, выясняется, что operator>>
здесь не возвращает bool
, а вместо этого возвращает "std::cin
". Вы не увидите никаких operator>>
, возвращающих значение bool
.
Итак, вопрос в том, как он преобразует std::basic_istream
в bool
?
Ответ: для этой цели вызывается оператор преобразования.
std::basic_istream
наследует operator bool()
из родительского std::basic_ios
explicit operator bool() const;
что позволяет преобразовать объект std::basic_istream
в bool
.
Нетрудно заметить, что он отмечен как explicit
(см. почему он помечен как explicit
), и все же он неявно преобразован в bool
в if
или while
.
Ответ на этот вопрос заключается в том, что if
или while
использует явное преобразование "неявно". (см. этот ответ by @R. Martinho Fernandes). Таким образом, if
, while
и for
являются одним из мест, где это "противоречивое преобразование" в bool
происходит неявно.