Иногда величина должны быть преобразована в
строковую форму, к примеру переменная типа int в объект
типа string, или наоборот, когда string
интерпретируется как int. Примеры таких преобразований
достаточно часты, когда данные из внутреннего
представления в программе преобразуются во внешнее,
например - конфигурационные файлы.
Стандарт языка C/C++ предусматривает ряд средств для выполнения таких преобразований. Однако они различаются по простоте использования, расширяемости и безопасности.
К примеру, существует ряд ограничений для
стандартной для языка C функции atoi:
sprintf,
или потери платформонезависимости при использовании таких
функций, как itoa.
int, long, и double.
complex или rational.
Стандартная функция C
strtol имеет те же же основные ограничения, хотя
предлагает более аккуратный контроль за процессом преобразования.
Однако, в общем случае такой контроль или
не требуется, или не используется.
Семейство функций scanf предоставляет еще больший
контроль, однако им не хватает надежности
и простоты использования.
Стандартная библиотека языка C++ содержит stringstream
как возможную основу для обсуждаемого форматирования
с преобразованием. Она предлагает удобный набор средств для
контроля за форматированием и преобразованием I/O из и в
произвольный тип через текст.
Для простых преобразований непосредственное использование stringstream
может быть неудобным (или введения дополнительных локальных
переменных и невозможности использования удобной инфиксной формы
выражений) или неочевидным и туманным (когда объекты типа stringstream
создаются как временные объекты в выражении). Локаль (facets)
содержит приемлемый набор средств для контроля за
представлением в текстовом виде, однако
сложность кода приводит к тому, что
использовать эти средства удобно только небольшму количеству
программистов.
Шаблон функции lexical_cast предлагает удобный и
целостный подход для поддержки распространенных преобразований в и
из произвольных типов, когда они
представлены в виде текста. Предлагаемое ей упрощение заключается в
использовании удобстве применения в выражениях. Для более сложных
преобразований, когда,
к примеру, требуется контролировать
точность, вместо lexical_cast
лучше использовать удобный подход
stringstream. Для преобразования одного числа в другое
вместо lexical_cast рекомендуется
использовать numeric_cast.
Детальное обсуждение всех опций и вопросов,
возникающих при форматировании строк,
включая сравнение stringstream, lexical_cast,
и других средств, можно найти в статье
Херба Саттера (Herb Sutter)
The String Formatters of Manor Farm.
Следующий пример преобразует аргументы командной строки в последовательность чисел:
int main(int argc, char * argv[])
{
using boost::lexical_cast;
using boost::bad_lexical_cast;
std::vector<short> args;
while(*++argv)
{
try
{
args.push_back(lexical_cast<short>(*argv));
}
catch(bad_lexical_cast &)
{
args.push_back(0);
}
}
...
}
Приведенный далее пример использует числовые величины в строковой выражении:
void log_message(const std::string &);
void log_errno(int yoko)
{
log_message("Error " + boost::lexical_cast<std::string>(yoko) + ": " + strerror(yoko));
}
Определенные в хидере "boost/lexical_cast.hpp" части библиотеки:
namespace boost
{
class bad_lexical_cast;
template<typename Target, typename Source>
Target lexical_cast(Source arg);
}
Тестовая программа - в файле lexical_cast_test.cpp.
template<typename Target, typename Source> Target lexical_cast(Source arg);
Функция возвращает результат передачи значение arg
в стандартный строковый поток и обратного преобразования в объект типа Target.
Когда тип Target это std::string или std::wstring,
извлечение из потока получает полное содержимое строки, включая пробелы, вместо
того, чтобы использовать operator>>
по умолчанию.
Если преобразование дает ошибку, то генерируется исключение
bad_lexical_cast.
Требования к аргументу и возвращаемому значению:
Source является OutputStreamable, что
значает, что определен operator<<,
который получает объект типа std::ostream
или std::wostream слева и объект типа аргумента
справа.
Target является InputStreamable, что
означает, что определен operator>>,
который берет объект типа std::istream
или std::wistream слева (left hand side) и
объект возвращаемого типа справа.
Source и Target следуют парадигме CopyConstructible [20.1.3].
Target следует парадигме DefaultConstructible,
что означает, что возможна
инифиализация по умолчанию объекта этого типа [8.5, 20.1.4].
Символьный тип используемого потока должен
быть char, если только Source
или Target не требуют использования потоков с wchar_t.
Типы
Source, которые требую
использования wchar_t-потоков это wchar_t,
wchar_t *, и std::wstring. Типы Target,
которые требуют использования wchar_t-потоков
это wchar_t и std::wstring.
Если требуется более высокий уровень контроля за преобразованием,
лучше использовать std::stringstream и std::wstringstream.
Когда требуется выполнить преобразования без использования потоков,
lexical_cast является неподходящим средством.
class bad_lexical_cast : public std::bad_cast
{
{
public:
... // same member function interface as std::exception
};
Для сообщений об ошибках преобразования в lexical_cast
используется генерация исключений.
Предыдущая версия шаблона lexical_cast
использовала установки точности в потоках по умолчанию для чтения и записи
чисел с плавающей запятой. Для числовых типов есть соответствующая
специализация в std::numeric_limits, а текущая версия шаблона
преобразования соответствующую точность.
Предыдущая версия шаблона lexical_cast
не поддерживала преобразование в или из типов на основе
wchar_t. Для
компиляторов, которые имеют полную поддержку для
wchar_t,
lexical_cast теперь поддерживает преобразование из wchar_t, wchar_t *,
и std::wstring и в wchar_t и std::wstring.
Предыдущая версия шаблона exical_cast
основывалась на предположении, что обычные
операторы извлечения из потока (stream extractor
operators) достаточны для чтения значений. Однако,
строковый ввод/вывод
асимметричен, так как пробелы играют роль
разделителей, а не входят в состав строк. Текущая
версия исправляет эту ошибку для std::string и, где возможно, std::wstring:
lexical_cast<std::string>("Hello, World") выполняется
успешно вместо ошибки с генерацией исключения
bad_lexical_cast.
Предыдущая версия шаблона lexical_cast
допускала небезопасное и бессмысленное преобразование к указателям. Текущая
версия генерирует исключение bad_lexical_cast для
преобразований в указатель:
lexical_cast<char *>("Goodbye, World") генерирует
исключение вместо неопределенного поведения в предыдущей версии.
последняя правка: 11.05.2005
библиотека BOOST C++
http://www.boost.org
перевод
Elijah Koziev
www.solarix.ru