Ответ 1
Особенностью std::stringstream
является то, что предполагается, что если поток используется как bool
, он преобразуется в true
, если поток по-прежнему действителен и false
, если он отсутствует. Например, это позволяет использовать простой синтаксис, если вы реализуете свою собственную версию лексического перевода.
(Для справки boost
содержит функцию шаблона под названием lexical_cast
, которая делает что-то похожее на следующую простую функцию шаблона.)
template <typename T, typename U>
T lexical_cast(const U & u) {
T t;
std::stringstream ss;
if (ss << u && ss >> t) {
return t;
} else {
throw bad_lexical_cast();
}
}
Если, например, вы работаете над проектом, в котором исключения запрещены, вы можете вместо этого перевернуть следующую версию.
template <typename T, typename U>
boost::optional<T> lexical_cast(const U & u) {
T t;
std::stringstream ss;
if (ss << u && ss >> t) {
return t;
} else {
return boost::none;
}
}
(Существуют различные способы улучшения вышеизложенного, этот код просто для примера).
operator void *
используется в приведенном выше виде:
-
ss << u
возвращает ссылку наss
. -
ss
неявно преобразован вvoid *
, который являетсяnullptr
, если операция потока завершилась неудачно, и не имеет значения null, если поток по-прежнему хорош. - Оператор
&&
прерывается быстро, в зависимости от значения истины этого указателя. - Вторая часть
ss >> t
запускается и возвращается и также преобразуется вvoid *
. - Если обе операции преуспели, мы можем вернуть потоковый результат
t
. Если либо не удалось, мы сообщим об ошибке.
Функция преобразования bool в основном представляет собой синтаксический сахар, который позволяет писать (и многое другое) в сжатом виде.
Недостаток фактического введения неявного преобразования bool заключается в том, что тогда std::stringstream
становится неявным образом конвертируемым в int
и многими другими типами, так как bool
неявно конвертируется в int
. Это в конечном итоге вызывает синтаксические кошмары в других местах.
Например, если std::stringstream
имеет неявное преобразование operator bool
, предположим, что у вас есть этот простой код:
std::stringstream ss;
int x = 5;
ss << x;
Теперь при разрешении перегрузки у вас есть две потенциальные перегрузки, чтобы рассмотреть (!), нормальный operator<<(std::stringstream &, int)
, и тот, в котором ss
преобразуется в bool
, затем продвигается до int
, а оператор битового сдвига может применяться operator<<(int, int)
, все из-за неявного преобразования в bool
...
Обходным путем является использование неявного преобразования в void *
вместо этого, которое может использоваться контекстно как bool, но на самом деле неявно конвертируется в bool или int.
В С++ 11 нам больше не нужен этот обходной путь, и нет причин, чтобы кто-то явно использовал преобразование void *
, поэтому он просто удалился.
(Я ищу ссылку, но я считаю, что значение этой функции было указано только тогда, когда она должна быть nullptr
против того, когда она не должна быть nullptr
, и что она была определена какой ненулевой показатель указателя он может дать.Таким образом, любой код, который полагался на версию void *
и не может быть тривиально реорганизован для использования версии bool
, в любом случае был бы некорректным.)
Обходной путь void *
все еще не без проблем. В boost была разработана более сложная идиома "безопасный bool" для кода pre-С++ 11, который на основе iiuc основан на чем-то вроде T*
, где t
является либо "типом, используемым один раз", как структурой, которая определенные в классе, реализующем идиому, или используя функцию-указатель-член для этого класса и используя возвращаемые значения, которые являются либо частной частной функцией-членом этого класса, либо nullptr. Идиома "safe bool" используется, например, во всех интеллектуальных указателях boost.
Несмотря на то, что весь этот беспорядок был очищен на С++ 11, введя explicit operator bool
.
Дополнительная информация здесь: Идиома safe-bool устарела в С++ 11?