From fa7f4ba7a729b6d42258ba7db9173d9b5d8e5e29 Mon Sep 17 00:00:00 2001
From: Daniel James
int
represented as
a string
, or vice-versa.lexical_cast
bad_lexical_cast
int
- represented as a string
, or vice-versa, when a string
- is interpreted as an int
. Such examples are common when converting
- between data types internal to a program and representation external to a
- program, such as windows and configuration files.
- - The standard C and C++ libraries offer a number of facilities for performing - such conversions. However, they vary with their ease of use, extensibility, and - safety. -
- For instance, there are a number of limitations with the family of standard C
- functions typified by atoi
:
-
sprintf
function, or the loss of
- portability associated with non-standard functions such as itoa
.
- int
, long
, and double
.
- complex
or rational
.
- strtol
have the same basic
- limitations, but offer finer control over the conversion process. However, for
- the common case such control is often either not required or not used. The scanf
- family of functions offer even greater control, but also lack safety and ease
- of use.
-
- The standard C++ library offers stringstream
for the kind of
- in-core formatting being discussed. It offers a great deal of control over the
- formatting and conversion of I/O to and from arbitrary types through text.
- However, for simple conversions direct use of stringstream
can be
- either clumsy (with the introduction of extra local variables and the loss of
- infix-expression convenience) or obscure (where stringstream
- objects are created as temporary objects in an expression). Facets provide a
- comprehensive concept and facility for controlling textual representation, but
- their perceived complexity and high entry level requires an extreme degree of
- involvement for simple conversions, and excludes all but a few programmers.
-
- The lexical_cast
function template offers a convenient and
- consistent form for supporting common conversions to and from arbitrary types
- when they are represented as text. The simplification it offers is in
- expression-level convenience for such conversions. For more involved
- conversions, such as where precision or formatting need tighter control than is
- offered by the default behavior of lexical_cast
, the conventional
- stringstream
approach is recommended. Where the conversions are
- numeric to numeric, numeric_cast
- may offer more reasonable behavior than lexical_cast
.
-
- For a good discussion of the options and issues involved in string-based
- formatting, including comparison of stringstream
, lexical_cast
,
- and others, see Herb Sutter's article,
- The String Formatters of Manor Farm. Also, take a look at the Performance section.
-
-
-The following example uses numeric data in a string expression: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"
:
- -Unit test defined innamespace boost -{ - class bad_lexical_cast; - template<typename Target, typename Source> - Target lexical_cast(const Source& arg); -} --
"lexical_cast_test.cpp"
.
- -
lexical_cast
-Returns the result of streamingtemplate<typename Target, typename Source> - Target lexical_cast(const Source& arg); --
arg
into a
- standard library string-based stream and then out as a Target
object.
- Where Target
is either std::string
- or std::wstring
, stream extraction takes the whole content
- of the string, including spaces, rather than relying on the default
- operator>>
behavior.
- If the conversion is unsuccessful, a
- bad_lexical_cast
exception is thrown.
- - The requirements on the argument and result types are: -
Source
is OutputStreamable, meaning that an operator<<
- is defined that takes a std::ostream
or std::wostream
object on the
- left hand side and an instance of the argument type on the right.
- Target
is InputStreamable, meaning that an operator>>
- is defined that takes a std::istream
or std::wistream
object on the left hand side
- and an instance of the result type on the right.
- Target
is CopyConstructible [20.1.3].
- Target
is DefaultConstructible, meaning that it is possible
- to default-initialize an object of that type [8.5, 20.1.4].
- char
unless
- either the Source
or the Target
requires wide-character
- streaming, in which case the underlying stream uses wchar_t
.
- Source
types that require wide-character streaming are wchar_t
,
- wchar_t *
, and std::wstring
. Target
types that
- require wide-character streaming are wchar_t
and std::wstring
.
-
- Where a higher degree of control is required over conversions, std::stringstream
- and std::wstringstream
offer a more appropriate path. Where non-stream-based conversions are
- required, lexical_cast
- is the wrong tool for the job and is not special-cased for such scenarios.
-
-
bad_lexical_cast
-Exception used to indicate runtimeclass bad_lexical_cast : public std::bad_cast -{ -public: - ... // same member function interface as std::exception -}; --
lexical_cast
- failure.
-
-Question: | -Why does lexical_cast<int8_t>("127") throw bad_lexical_cast ? |
-
Answer: | -The type int8_t is a typedef to char or signed char .
- Lexical conversion to these types is simply reading a byte from source but since the source has
- more than one byte, the exception is thrown.
- Please use other integer types such as int or short int . If bounds checking
- is important, you can also call numeric_cast:
-numeric_cast<int8_t>(lexical_cast<int>("127"));- |
-
Question: | What does lexical_cast<std::string> of an int8_t or uint8_t not do what I expect? |
-
Answer: | As above, note that int8_t and uint8_t are actually chars and are formatted as such. To avoid this, cast to an integer type first:
- lexical_cast<std::string>(static_cast<int>(n));- |
-
Question: | -The implementation always resets the ios_base::skipws flag of an underlying stream object. It breaks my operator>> that works only in presence of this flag. Can you remove code that resets the flag? |
-
Answer: | -May be in a future version. There is no requirement in [N1973] to reset the flag but remember that [N1973] is not yet accepted by the committee. By the way, it's a great opportunity to make your operator>> conform to the standard. Read a good C++ book, study std::sentry and ios_state_saver.
- |
-
Question: | -Why std::cout << boost::lexical_cast<unsigned int>("-1"); does not throw, but outputs 4294967295? |
-
Answer: | -boost::lexical_cast has the behavior of stringstream , which uses num_get functions of std::locale to convert numbers. If we look at the [22.2.2.1.2] of Programming languages — C++, we'll see, that num_get uses the rules of scanf for conversions. And in the C99 standard for unsigned input value minus sign is optional, so if a negative number is read, no errors will arise and the result will be the two's complement.
- |
-
Target
from Source
on some conversions (like conversions from string to string, from char array to string, from char to char and others).Source
and Target
- types. Refer to [Tuning] for more details.
- lexical_cast
used the default stream
- precision for reading and writing floating-point numbers. For numerics that
- have a corresponding specialization of std::numeric_limits
, the
- current version now chooses a precision to match. lexical_cast
did not support conversion
- to or from any wide-character-based types. For compilers with full language
- and library support for wide characters, lexical_cast
now supports
- conversions from wchar_t
, wchar_t *
, and std::wstring
- and to wchar_t
and std::wstring
. lexical_cast
assumed that the conventional
- stream extractor operators were sufficient for reading values. However, string
- I/O is asymmetric, with the result that spaces play the role of I/O separators
- rather than string content. The current version fixes this error for std::string
- and, where supported, std::wstring
: lexical_cast<std::string>("Hello,
- World")
succeeds instead of failing with a bad_lexical_cast
- exception. lexical_cast
allowed unsafe and meaningless
- conversions to pointers. The current version now throws a bad_lexical_cast
- for conversions to pointers: lexical_cast<char *>("Goodbye, World")
- now throws an exception instead of causing undefined behavior.
--
From->To | lexical_cast | std::stringstream with construction | std::stringstream without construction | sscanf /sprintf |
string->char | <1 | 91 | 7 | 10 |
string->int | 7 | 115 | 23 | 18 |
string->unsigned int | 7 | 117 | 22 | 17 |
string->bool | <1 | 104 | 19 | 10 |
string->float | 13 | 172 | 60 | 33 |
char->string | 7 | 105 | 16 | 12 |
int->string | 15 | 131 | 21 | 17 |
unsigned int->string | 14 | 125 | 21 | 17 |
bool->string | 7 | 122 | 24 | 12 |
float->string | 124 | 223 | 115 | 48 |
char*->string | 9 | 123 | 20 | --- |
int->int | <1 | 120 | 26 | --- |
float->float | <1 | 262 | 142 | --- |