Почему std :: basic_ios перегружает унарный оператор логического отрицания? - PullRequest
9 голосов
/ 11 июля 2010

Базовый класс потоков ввода-вывода C ++ std::basic_ios определяет operator void*() для возврата !fail() и operator!() для возврата fail().Это заставляет меня задуматься, зачем вообще нужен operator!().Конечно, !is также будет работать, неявно вызывая operator void*() и отрицая его результат.

Я что-то здесь упускаю или чисто по историческим причинам определено std::basic_ios::operator!()?

A вопрос на comp.lang.c ++. Модерируемый также не принес никаких ответов.

Ответы [ 3 ]

6 голосов
/ 22 августа 2010

В старых (читай: вскоре после cfront) компиляторах C ++ компилятору не гарантировалось неявно вызывать операторы типов при необходимости.Если iostream не имеет объявленного operator !, вы не можете ожидать, что !cout будет работать во всех случаях.C ++ 89 (или как там назывался стандарт до C ++ 98) просто оставил область неопределенной.

По этой же причине operator void*() был перегружен, а не operator int или operator bool.(bool даже не существовал как собственный тип в стандарте на тот момент.) Я помню, как мой профессор говорил мне, что if() под капотом ожидал void* в C ++, потому что этот тип мог действовать кактип «superset» относительно тех типов результатов выражения, которые будут переданы в оператор if, но я нигде не нашел это прописанным.

Это было во времена gcc 2, когда большинство людейне поддерживал шаблоны или исключения, или, если они это делали, не поддерживал их полностью, поэтому метапрограммирование C ++ с помощью шаблонов все еще было теоретическим упражнением, и вы должны убедиться, что operator new не возвращает нулевой указатель.

Это сводило меня с ума в течение нескольких лет.

Интересная выдержка из Страуструпа Язык программирования C ++ , 3-е изд.(1997), стр. 276:

Типы istream и ostream полагаются на функцию преобразования для включения операторов, таких как

while (cin >> x) cout << x;

Операция ввода cin >> x возвращает istream & .Это значение неявно преобразуется в значение, указывающее состояние cin .Затем значение можно проверить с помощью , тогда как .Однако обычно не хорошая идея для определения неявного преобразования из одного типа в другой таким образом, что при преобразовании теряется информация.

Существует многоС ++, который кажется милой или умной победой над последовательной.Я бы не возражал, если бы C ++ был достаточно умен, чтобы обрабатывать цикл, описанный выше, так:

while (!(cin >> x).fail()) cout << x;

, потому что это, хотя и более многословно и более пунктуально, понятнее начинающему программисту.* ... На самом деле, если подумать, мне не нравится ни одна из этих конструкций.Объясните это:

for(;;)
{   cin >> x;
    if(!cin)
        break;
    cout << x;
}

Почему мне это нравится больше?Потому что эта версия значительно упрощает процесс расширения кода, скажем, для обработки двух операций чтения за раз вместо одного.Например, «Существующий код копирует последовательность значений с плавающей запятой. Мы хотим, чтобы вы изменили ее, чтобы она объединяла значения с плавающей запятой и записывала их по два на строку, поскольку теперь мы используем комплексные числа».

Но я отвлекся.

2 голосов
/ 22 августа 2010

Ладно, вот тут и закончил, я пошел и спросил на comp.lang.c ++. Модерируемый .

Сначала результаты были такими же плохими, как и здесь, но в итоге Ответ Даниэля Крюглера согласился с моим подозрением, что для operator!() нет технических причин:

Мне сказали, что это дополнительное объявление было добавлено, чтобы подчеркнуть симметрию между «истинным» случаем и его отрицанием, просто как руководство для читателя, не более того.Чтобы быть справедливым, идиома

operator void*

была довольно новой в это время, и с учетом этого вывод, поддержка синтаксиса которого обеспечивается этой функцией, не сразу очевиден.Кроме этого не было никаких технических причин для этого.[...]

1 голос
/ 11 июля 2010

Рассматривая реализацию MinGW, которая поставляется с Codeblocks, показывает мне этот код:

  operator void*() const
  { return this->fail() ? 0 : const_cast<basic_ios*>(this); }

  bool
  operator!() const
  { return this->fail(); }

Мне кажется, что operator void*() const предназначен для большего количества применений, чем только для проверки успеха. Кроме того, он также служит оператором приведения (мы возвращаем this). Прямо сейчас я немного почесываю голову, почему мы можем захотеть привести this к void*. Но остальное совершенно ясно - если у вас все равно есть ошибочный поток, вы также можете вернуть ноль.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...