istringstream is(s);
T t;
if (!(is >> t)) throw bad_from_string();
return t;
}
Рассмотрим пример.
double d = from_string
void do_something(const string& s)
try
{
int i = from_string
// ...
}
catch (bad_from_string e) {
error ("Неправильная строка ввода",s);
}
Дополнительная сложность функции from_string()
to_string() объясняется тем, что класс string может представлять значения многих типов. Это значит, что каждый раз мы должны указывать, какой тип значений хотим извлечь из объекта класса string. Кроме того, это значит, что класс string, который мы изучаем, может не хранить значение типа, который мы ожидаем. Рассмотрим пример.int d = from_string
Итак, возможна ошибка, которую мы представили в виде исключения типа bad_from_string
from_string() (или эквивалентная) играет важную роль в серьезных текстовых приложениях, поскольку нам необходимо извлекать числовые значения из текстовых полей. В разделе 16.4.3 было показано, как эквивалентная функция get_int() используется в графическом пользовательском интерфейсе.Обратите внимание на то, что функции to_string()
from_string() очень похожи. Фактически они являются обратными друг другу; иначе говоря (игнорируя детали, связанные с пробелами, округлением и т.д.), для каждого “разумного типа T” имеемs==to_string(from_string
и
t==from_string
Здесь слово “разумный” означает, что тип T
>> и соответствующий оператор <<. to_string()
from_string() используют класс stringstream для выполнения всей работы. Это наблюдение было использовано для определения универсальной операции конвертирования двух произвольных типов с согласованными операциями << и >>.struct bad_lexical_cast:std::bad_cast
{
const char* what() const { return "bad cast"; }
};
template
Target lexical_cast(Source arg)
{
std::stringstream interpreter;
Target result;
if (!(interpreter << arg) // записываем arg в поток
|| !(interpreter >> result) // считываем result из потока
|| !(interpreter >> std::ws).eof()) // поток пуст?
throw bad_lexical_cast();
return result;
}
Довольно забавно и остроумно, что инструкция !(interpreter>>std::ws).eof()
stringstream после извлечения результата. Пробелы допускаются, но кроме них в потоке ввода может не остаться никаких других символов, и мы должны реагировать на эту ситуацию, как на обнаружение конца файла. Итак, если мы пытаемся считать целое число int из объекта класса string, используя класс lexical_cast, то в результате выражения lexical_cast("123") и lexical_cast("123") будут считаться допустимыми, а выражение lexical_cast("123.5") — нет из-за последней пятерки.Довольно элегантное, хотя и странное, имя lexical_cast
boost, которую мы будем использовать для сравнения регулярных выражений в разделах 23.6–23.9. В будущем она станет частью новых версий стандарта языка С++ .23.3. Потоки ввода-вывода
iostream
Стандартные потоки организованы в виде иерархии классов (см. раздел 14.3).