Compare commits

...
12 Commits
Author SHA1 Message Date
nobody f4c8dd464b This commit was manufactured by cvs2svn to create tag
'Version_1_30_1'.

[SVN r19444]
2003-08-04 17:55:29 +00:00
Terje Slettebø 3804825f6c no message
[SVN r18238]
2003-04-12 08:02:14 +00:00
Terje Slettebø fdd5ca3353 Merged from trunk
[SVN r18237]
2003-04-11 22:15:04 +00:00
Terje Slettebø 6e077f97fc BOOST_MSVC<=1200 fix from Terje
[SVN r18019]
2003-03-19 21:25:45 +00:00
Beman Dawes d9eed4150b BOOST_MSVC<=1200 fix from Terje
[SVN r18002]
2003-03-19 12:14:32 +00:00
Dave Abrahams 62014cf4b6 Commit Terje's changes
[SVN r17982]
2003-03-18 23:55:14 +00:00
Terje Slettebø aad1bfda73 Updated Changes section
[SVN r17922]
2003-03-14 20:32:51 +00:00
Terje Slettebø 3f452717cf no message
[SVN r17921]
2003-03-14 20:17:47 +00:00
Beman Dawes b06d9f5639 overloading fix + less permissive wide character support
[SVN r17893]
2003-03-13 17:27:06 +00:00
Beman Dawes 1b796221b4 BOOST_NO_STD_WSTRING
[SVN r17872]
2003-03-13 00:36:13 +00:00
Beman Dawes 027afb3a87 update from Kevlin and Terje
[SVN r17861]
2003-03-12 21:33:16 +00:00
nobody 07cb73a96c This commit was manufactured by cvs2svn to create branch 'RC_1_30_0'.
[SVN r17693]
2003-03-01 19:43:06 +00:00
3 changed files with 614 additions and 385 deletions
+164 -35
View File
@@ -1,31 +1,38 @@
// boost lexical_cast.hpp header -------------------------------------------//
// See http://www.boost.org/libs/conversion for documentation.
#ifndef BOOST_LEXICAL_CAST_INCLUDED #ifndef BOOST_LEXICAL_CAST_INCLUDED
#define BOOST_LEXICAL_CAST_INCLUDED #define BOOST_LEXICAL_CAST_INCLUDED
// Boost lexical_cast.hpp header -------------------------------------------//
//
// See http://www.boost.org for most recent version including documentation.
// See end of this header for rights and permissions.
//
// what: lexical_cast custom keyword cast // what: lexical_cast custom keyword cast
// who: contributed by Kevlin Henney, with alternative naming, behaviors // who: contributed by Kevlin Henney,
// and fixes contributed by Dave Abrahams, Daryle Walker and other // enhanced with contributions from Terje Slettebø,
// Boosters on the list // with additional fixes and suggestions from Gennaro Prota,
// when: November 2000 // Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov,
// where: tested with MSVC 6.0, BCC 5.5, and g++ 2.91 // and other Boosters
// when: November 2000, March 2003
#include <string>
#include <typeinfo>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/limits.hpp>
#include <boost/throw_exception.hpp>
#include <boost/type_traits/is_pointer.hpp>
// Some sstream implementations are broken for the purposes of lexical cast. #ifdef BOOST_NO_STRINGSTREAM
# if defined(BOOST_NO_STRINGSTREAM) #include <strstream>
# define BOOST_LEXICAL_CAST_USE_STRSTREAM
# endif
#ifdef BOOST_LEXICAL_CAST_USE_STRSTREAM
# include <strstream>
#else #else
# include <sstream> #include <sstream>
#endif #endif
#include <typeinfo> #if defined(BOOST_NO_STRINGSTREAM) || \
defined(BOOST_NO_STD_WSTRING) || \
defined(BOOST_NO_STD_LOCALE) || \
defined(BOOST_NO_INTRINSIC_WCHAR_T)
#define DISABLE_WIDE_CHAR_SUPPORT
#endif
namespace boost namespace boost
{ {
@@ -33,35 +40,159 @@ namespace boost
class bad_lexical_cast : public std::bad_cast class bad_lexical_cast : public std::bad_cast
{ {
public: public:
// constructors, destructors, and assignment operator defaulted bad_lexical_cast() :
source(&typeid(void)), target(&typeid(void))
// function inlined for brevity and consistency with rest of library {
virtual const char * what() const throw() }
bad_lexical_cast(
const std::type_info &s,
const std::type_info &t) :
source(&s), target(&t)
{
}
const std::type_info &source_type() const
{
return *source;
}
const std::type_info &target_type() const
{
return *target;
}
virtual const char *what() const throw()
{ {
return "bad lexical cast: " return "bad lexical cast: "
"source type value could not be interpreted as target"; "source type value could not be interpreted as target";
} }
virtual ~bad_lexical_cast() throw()
{
}
private:
const std::type_info *source;
const std::type_info *target;
}; };
namespace detail // selectors for choosing stream character type
{
template<typename Type>
struct stream_char
{
typedef char type;
};
#ifndef DISABLE_WIDE_CHAR_SUPPORT
template<>
struct stream_char<wchar_t>
{
typedef wchar_t type;
};
template<>
struct stream_char<wchar_t *>
{
typedef wchar_t type;
};
template<>
struct stream_char<const wchar_t *>
{
typedef wchar_t type;
};
template<>
struct stream_char<std::wstring>
{
typedef wchar_t type;
};
#endif
template<typename TargetChar, typename SourceChar>
struct widest_char
{
typedef TargetChar type;
};
template<>
struct widest_char<char, wchar_t>
{
typedef wchar_t type;
};
}
namespace detail // stream wrapper for handling lexical conversions
{
template<typename Target, typename Source>
class lexical_stream
{
public:
lexical_stream()
{
stream.unsetf(std::ios::skipws);
if(std::numeric_limits<Target>::is_specialized)
stream.precision(std::numeric_limits<Target>::digits10 + 1);
else if(std::numeric_limits<Source>::is_specialized)
stream.precision(std::numeric_limits<Source>::digits10 + 1);
}
~lexical_stream()
{
#if defined(BOOST_NO_STRINGSTREAM)
stream.freeze(false);
#endif
}
bool operator<<(const Source &input)
{
return !(stream << input).fail();
}
template<typename InputStreamable>
bool operator>>(InputStreamable &output)
{
return !is_pointer<InputStreamable>::value &&
stream >> output &&
(stream >> std::ws).eof();
}
bool operator>>(std::string &output)
{
#if defined(BOOST_NO_STRINGSTREAM)
stream << '\0';
#endif
output = stream.str();
return true;
}
#ifndef DISABLE_WIDE_CHAR_SUPPORT
bool operator>>(std::wstring &output)
{
output = stream.str();
return true;
}
#endif
private:
typedef typename widest_char<
typename stream_char<Target>::type,
typename stream_char<Source>::type>::type char_type;
#if defined(BOOST_NO_STRINGSTREAM)
std::strstream stream;
#elif defined(BOOST_NO_STD_LOCALE)
std::stringstream stream;
#else
std::basic_stringstream<char_type> stream;
#endif
};
}
template<typename Target, typename Source> template<typename Target, typename Source>
Target lexical_cast(Source arg) Target lexical_cast(Source arg)
{ {
# ifdef BOOST_LEXICAL_CAST_USE_STRSTREAM detail::lexical_stream<Target, Source> interpreter;
std::strstream interpreter; // for out-of-the-box g++ 2.95.2
# else
std::stringstream interpreter;
# endif
Target result; Target result;
if(!(interpreter << arg) || !(interpreter >> result) || if(!(interpreter << arg && interpreter >> result))
!(interpreter >> std::ws).eof()) throw_exception(bad_lexical_cast(typeid(Target), typeid(Source)));
throw bad_lexical_cast();
return result; return result;
} }
} }
// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. // Copyright Kevlin Henney, 2000-2003. All rights reserved.
// //
// Permission to use, copy, modify, and distribute this software for any // Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and // purpose is hereby granted without fee, provided that this copyright and
@@ -69,8 +200,6 @@ namespace boost
// //
// This software is provided "as is" without express or implied warranty. // This software is provided "as is" without express or implied warranty.
#ifdef BOOST_LEXICAL_CAST_USE_STRSTREAM #undef DISABLE_WIDE_CHAR_SUPPORT
# undef BOOST_LEXICAL_CAST_USE_STRSTREAM
#endif #endif
#endif
+177 -206
View File
@@ -1,99 +1,95 @@
<!-- saved from url=(0022)http://internet.e-mail -->
<!doctype html public "-//W3C//DTD HTML Transitional 4.0//EN"> <!doctype html public "-//W3C//DTD HTML Transitional 4.0//EN">
<html> <html>
<head> <head>
<title>lexical_cast</title> <title>lexical_cast</title>
<meta name="author" content="Kevlin Henney, mailto:kevlin@curbralan.com"> <meta name="author" content="Kevlin Henney, mailto:kevlin@curbralan.com">
<meta name="generator" content="Microsoft FrontPage 4.0"> <meta name="generator" content="Microsoft FrontPage 4.0">
</head> </head>
<body bgcolor="#FFFFFF" text="#000000">
<body bgcolor="#FFFFFF" text="#000000"> <h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Header
<a href="../../boost/lexical_cast.hpp">boost/lexical_cast.hpp</a></h1>
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Header <ul type="square">
<a href="../../boost/lexical_cast.hpp">boost/lexical_cast.hpp</a></h1> <li>
<a href="#motivation">Motivation</a></li>
<ul> <li>
<li><a href="#motivation">Motivation</a></li> <a href="#examples">Examples</a></li>
<li><a href="#examples">Examples</a></li> <li>
<li><a href="#synopsis">Synopsis</a></li> <a href="#synopsis">Synopsis</a></li>
<li><a href="#lexical_cast"><code>lexical_cast</code></a></li> <li>
<li><a href="#bad_lexical_cast"><code>bad_lexical_cast</code></a></li> <a href="#lexical_cast"><code>lexical_cast</code></a></li>
<li><a href="#portability">Portability</a></li> <li>
<li><a href="#future">Future directions</a></li> <a href="#bad_lexical_cast"><code>bad_lexical_cast</code></a></li>
</ul> <li>
<a href="#changes">Changes</a></li>
<hr> </ul>
<h2><a name="motivation">Motivation</a></h2> <hr>
<h2><a name="motivation">Motivation</a></h2>
Sometimes a value must be converted to a literal text form, such as an Sometimes a value must be converted to a literal text form, such as an <code>int</code>
<code>int</code> represented as a <code>string</code>, or vice-versa, when represented as a <code>string</code>, or vice-versa, when a <code>string</code>
a <code>string</code> is interpreted as an <code>int</code>. Such examples is interpreted as an <code>int</code>. Such examples are common when converting
are common when converting between data types internal to a program and between data types internal to a program and representation external to a
representation external to a program, such as windows and configuration files. program, such as windows and configuration files.
<p> <p>
The standard C and C++ libraries offer a number of facilities for performing The standard C and C++ libraries offer a number of facilities for performing
such conversions. However, they vary with their ease of use, extensibility, such conversions. However, they vary with their ease of use, extensibility, and
and safety. safety.
<p> <p>
For instance, there are a number of limitations with the family of standard C For instance, there are a number of limitations with the family of standard C
functions typified by <code>atoi</code>: functions typified by <code>atoi</code>:
<ul> <ul type="square">
<li> <li>
Conversion is supported in one direction only: from text to Conversion is supported in one direction only: from text to internal data type.
internal data type. Converting the other way using the C library Converting the other way using the C library requires either the inconvenience
requires either the inconvenience and compromised safety of the and compromised safety of the <code>sprintf</code> function, or the loss of
<code>sprintf</code> function, or the loss of portability associated portability associated with non-standard functions such as <code>itoa</code>.
with non-standard functions such as <code>itoa</code>. </li>
</li> <li>
<li> The range of types supported is only a subset of the built-in numeric types,
The range of types supported is only a subset of the built-in numeric namely <code>int</code>, <code>long</code>, and <code>double</code>.
types, namely <code>int</code>, <code>long</code>, </li>
and <code>double</code>. <li>
</li> The range of types cannot be extended in a uniform manner. For instance,
<li> conversion from string representation to <code>complex</code> or <code>rational</code>.
The range of types cannot be extended in a uniform manner. For </li>
instance, conversion from string representation to </ul>
<code>complex</code> or <code>rational</code>. The standard C functions typified by <code>strtol</code> have the same basic
</li> limitations, but offer finer control over the conversion process. However, for
</ul> the common case such control is often either not required or not used. The <code>scanf</code>
The standard C functions typified by <code>strtol</code> have the same basic family of functions offer even greater control, but also lack safety and ease
limitations, but offer finer control over the conversion process. However, for of use.
the common case such control is often either not required or not used. The <p>
<code>scanf</code> family of functions offer even greater control, but also The standard C++ library offers <code>stringstream</code> for the kind of
lack safety and ease of use. in-core formatting being discussed. It offers a great deal of control over the
<p> formatting and conversion of I/O to and from arbitrary types through text.
The standard C++ library offers <code>stringstream</code> for the kind of However, for simple conversions direct use of <code>stringstream</code> can be
in-core formatting being discussed. It offers a great deal of control over the either clumsy (with the introduction of extra local variables and the loss of
formatting and conversion of I/O to and from arbitrary types through text. infix-expression convenience) or obscure (where <code>stringstream</code>
However, for simple conversions direct use of <code>stringstream</code> can be objects are created as temporary objects in an expression). Facets provide a
either clumsy (with the introduction of extra local variables and the loss of comprehensive concept and facility for controlling textual representation, but
infix-expression convenience) or obscure (where <code>stringstream</code> their perceived complexity and high entry level requires an extreme degree of
objects are created as temporary objects in an expression). Facets provide a involvement for simple conversions, and excludes all but a few programmers.
comprehensive concept and facility for controlling textual representation, but <p>
their relatively high entry level requires an extreme degree of involvement The <code>lexical_cast</code> function template offers a convenient and
for simple conversions. consistent form for supporting common conversions to and from arbitrary types
<p> when they are represented as text. The simplification it offers is in
The <code>lexical_cast</code> template function offers a convenient and consistent expression-level convenience for such conversions. For more involved
form for supporting common conversions to and from arbitrary types when they are conversions, such as where precision or formatting need tighter control than is
represented as text. The simplification it offers is in expression-level offered by the default behavior of <code>lexical_cast</code>, the conventional <code>
convenience for such conversions. For more involved conversions, such as where stringstream</code> approach is recommended. Where the conversions are
precision or formatting need tighter control than is offered by the default numeric to numeric, <code><a href="cast.htm#numeric_cast">numeric_cast</a></code>
behavior of <code>lexical_cast</code>, the conventional may offer more reasonable behavior than <code>lexical_cast</code>.
<code>stringstream</code> approach is recommended. Where the conversions are <p>
numeric to numeric, <code><a href="cast.htm#numeric_cast">numeric_cast</a></code> For a good discussion of the options and issues involved in string-based
may offer more reasonable behavior than <code>lexical_cast</code>. formatting, including comparison of <code>stringstream</code>, <code>lexical_cast</code>,
<p> and others, see Herb Sutter's article, <a href="http://www.gotw.ca/publications/mill19.htm">
For a good discussion of the options and issues involved in string-based formatting, <i>The String Formatters of Manor Farm</i></a>.
including comparison of <code>stringstream</code>, <code>lexical_cast</code>, and <p>
others, see Herb Sutter's article, <a href="http://www.gotw.ca/publications/mill19.htm"> <hr>
<i>The String Formatters of Manor Farm</i></a>. <h2><a name="examples">Examples</a></h2>
<p> The following example treats command line arguments as a sequence of numeric
data: <blockquote>
<hr> <pre>
<h2><a name="examples">Examples</a></h2>
The following example treats command line arguments as a sequence of numeric data:
<blockquote>
<pre>
int main(int argc, char * argv[]) int main(int argc, char * argv[])
{ {
using boost::lexical_cast; using boost::lexical_cast;
@@ -115,11 +111,8 @@ int main(int argc, char * argv[])
... ...
} }
</pre> </pre>
</blockquote> </blockquote>The following example uses numeric data in a string expression: <blockquote>
<pre>
The following example uses numeric data in a string expression:
<blockquote>
<pre>
void log_message(const std::string &amp;); void log_message(const std::string &amp;);
void log_errno(int yoko) void log_errno(int yoko)
@@ -127,15 +120,12 @@ void log_errno(int yoko)
log_message(&quot;Error &quot; + boost::lexical_cast&lt;std::string&gt;(yoko) + &quot;: &quot; + strerror(yoko)); log_message(&quot;Error &quot; + boost::lexical_cast&lt;std::string&gt;(yoko) + &quot;: &quot; + strerror(yoko));
} }
</pre> </pre>
</blockquote> </blockquote>
<hr>
<hr> <h2><a name="synopsis">Synopsis</a></h2>
<h2><a name="synopsis">Synopsis</a></h2> Library features defined in <a href="../../boost/lexical_cast.hpp"><code>&quot;boost/lexical_cast.hpp&quot;</code></a>:
<blockquote>
Library features defined in <a href="../../boost/lexical_cast.hpp"><code>&quot;boost/lexical_cast.hpp&quot;</code></a>: <pre>
<blockquote>
<pre>
namespace boost namespace boost
{ {
class <a href="#bad_lexical_cast">bad_lexical_cast</a>; class <a href="#bad_lexical_cast">bad_lexical_cast</a>;
@@ -143,110 +133,91 @@ namespace boost
Target <a href="#lexical_cast">lexical_cast</a>(Source arg); Target <a href="#lexical_cast">lexical_cast</a>(Source arg);
} }
</pre> </pre>
</blockquote> </blockquote>Unit test defined in <a href="lexical_cast_test.cpp"><code>&quot;lexical_cast_test.cpp&quot;</code></a>.
<p>
Test harness defined in <a href="lexical_cast_test.cpp"><code>&quot;lexical_cast_test.cpp&quot;</code></a>. <hr>
<p> <h2><a name="lexical_cast"><code>lexical_cast</code></a></h2>
<blockquote>
<hr> <pre>
<h2><a name="lexical_cast"><code>lexical_cast</code></a></h2>
<blockquote>
<pre>
template&lt;typename Target, typename Source&gt; template&lt;typename Target, typename Source&gt;
Target lexical_cast(Source arg); Target lexical_cast(Source arg);
</pre> </pre>
</blockquote> </blockquote>Returns the result of streaming <code>arg</code> into a
standard library string-based stream and then out as a <code>Target</code> object.
Returns the result of streaming <code>arg</code> into a <code>std::stringstream</code> and then Where <code>Target</code> is either <code>std::string</code>
out as a <code>Target</code> object. If the conversion is unsuccessful, a or <code>std::wstring</code>, stream extraction takes the whole content
<a href="#bad_lexical_cast"><code>bad_lexical_cast</code></a> exception is thrown. of the string, including spaces, rather than relying on the default
<p> <code>operator&gt;&gt;</code> behavior.
The requirements on the argument and result types are: If the conversion is unsuccessful, a <a href="#bad_lexical_cast">
<ul> <code>bad_lexical_cast</code></a> exception is thrown.
<li> <p>
<code>Source</code> is <i>OutputStreamable</i>, meaning that an The requirements on the argument and result types are:
<code>operator&lt;&lt;</code> is defined that takes a <ul type="square">
<code>std::ostream</code> object on the left hand side and an instance <li>
of the argument type on the right. <code>Source</code> is <i>OutputStreamable</i>, meaning that an <code>operator&lt;&lt;</code>
</li> is defined that takes a <code>std::ostream</code> or <code>std::wostream</code> object on the
<li> left hand side and an instance of the argument type on the right.
Both <code>Source</code> and <code>Target</code> are <i>CopyConstructible</i> [20.1.3]. </li>
</li> <li>
<li> <code>Target</code> is <i>InputStreamable</i>, meaning that an <code>operator&gt;&gt;</code>
<code>Target</code> is <i>InputStreamable</i>, meaning that an is defined that takes a <code>std::istream</code> or <code>std::wistream</code> object on the left hand side
<code>operator&gt;&gt;</code> is defined that takes a and an instance of the result type on the right.
<code>std::istream</code> object on the left hand side and an instance </li>
of the result type on the right. <li>
</li> Both <code>Source</code> and <code>Target</code> are <i>CopyConstructible</i> [20.1.3].
<li> </li>
<code>Target</code> is <i>DefaultConstructible</i>, meaning that it is <li>
possible to <i>default-initialize</i> an object of that type [8.5, 20.1.3]. <code>Target</code> is <i>DefaultConstructible</i>, meaning that it is possible
</li> to <i>default-initialize</i> an object of that type [8.5, 20.1.4].
<li> </li>
<code>Target</code> is <i>Assignable</i> [23.1]. </ul>
</li> The character type of the underlying stream is assumed to be <code>char</code> unless
</ul> either the <code>Source</code> or the <code>Target</code> requires wide-character
<p> streaming, in which case the underlying stream uses <code>wchar_t</code>.
<code>Source</code> types that require wide-character streaming are <code>wchar_t</code>,
<hr> <code>wchar_t *</code>, and <code>std::wstring</code>. <code>Target</code> types that
<h2><a name="bad_lexical_cast"><code>bad_lexical_cast</code></a></h2> require wide-character streaming are <code>wchar_t</code> and <code>std::wstring</code>.
<p>
<blockquote> Where a higher degree of control is required over conversions, <code>std::stringstream</code>
<pre> and <code>std::wstringstream</code> offer a more appropriate path. Where non-stream-based conversions are
required, <code>lexical_cast</code>
is the wrong tool for the job and is not special-cased for such scenarios.
<p>
<hr>
<h2><a name="bad_lexical_cast"><code>bad_lexical_cast</code></a></h2>
<blockquote>
<pre>
class bad_lexical_cast : public std::bad_cast class bad_lexical_cast : public std::bad_cast
{ {
public: public:
virtual const char * what() const throw(); ... // <i>same member function interface as</i> std::exception
}; };
</pre> </pre>
</blockquote> </blockquote>Exception used to indicate runtime <a href="#lexical_cast"><code>lexical_cast</code></a>
failure.
Exception used to indicate runtime <a href="#lexical_cast"><code>lexical_cast</code></a> failure. <hr>
<p> <h2><a name="changes">Changes</a></h2>
<ul type="square">
<hr> <li>The previous version of <code>lexical_cast</code> used the default stream precision for reading
<h2><a name="portability">Portability</a></h2> and writing floating-point numbers. For numerics that have a corresponding specialization of
<code>std::numeric_limits</code>, the current version now chooses a precision to match.
To date the code and test harness have been compiled successfully using <li>The previous version of <code>lexical_cast</code> did not support conversion to or from any
Microsoft Visual C++ 6.0, Borland C++ 5.5, and GNU g++ 2.91. Tests have run successfully for wide-character-based types. For compilers with full language and library support for wide characters,
Microsoft Visual C++ 6.0 and Borland C++ 5.5. For g++ streams interpret any integer, rather than <code>lexical_cast</code> now supports conversions from <code>wchar_t</code>, <code>wchar_t *</code>,
just <code>0</code> and <code>1</code>, as valid for <code>bool</code>; the other tests pass and <code>std::wstring</code> and to <code>wchar_t</code> and <code>std::wstring</code>.
without problem. The deprecated standard header <code>&lt;strstream&gt;</code> is used in <li>The previous version of <code>lexical_cast</code> assumed that the conventional stream extractor
preference to the standard <code>&lt;sstream&gt;</code> header for out-of-the-box g++ support. operators were sufficient for reading values. However, string I/O is asymmetric, with the result
<p> that spaces play the role of I/O separators rather than string content. The current version fixes
this error for <code>std::string</code> and, where supported, <code>std::wstring</code>:
<hr> <code>lexical_cast&lt;std::string&gt;("Hello, World")</code> succeeds instead of failing with
<h2><a name="future">Future directions</a></h2> a <code>bad_lexical_cast</code> exception.
<li>The previous version of <code>lexical_cast</code> allowed unsafe and meaningless conversions to
<ul> pointers. The current version now throws a <code>bad_lexical_cast</code> for conversions to pointers:
<li> <code>lexical_cast&lt;char *&gt;("Goodbye, World")</code> now throws an exception instead of
Improved string handling, correctly accommodating wide character strings, incompatible causing undefined behavior.
<code>basic_string</code> types, and empty strings. </ul>
</li> <p>
<li> <hr>
Optimize the use of a stream away for identity conversions. <div align="right"><small><i>&copy; Copyright Kevlin Henney, 2000&#150;2003</i></small></div>
</li> </body>
<li>
An <code>interpret_cast</code> that performs a <i>do-something-reasonable</i> conversion between
types. It would, for instance, select between <code>numeric_cast</code> and <code>lexical_cast</code>
based on <code>std::numeric_limits&lt;&gt;::is_specialized</code>. This would be an interesting
project, but there are no concrete plans to pursue this at the moment.
</li>
<li>
It is also worth mentioning future <i>non-directions</i>: anything that involves adding extra
arguments for a conversion operation is not being considered. A custom keyword cast, such as
<code>lexical_cast</code>, is intended to look like a built-in cast operator: built-in cast operators
take only a single operand. Where a higher degree of control is required over conversions, the
standard <code>stringstream</code> offers a more appropriate path. Where non-stream-based conversions
are required, <code>lexical_cast</code> is the wrong tool for the job, and so it won't be special-cased
for such scenarios.
</li>
</ul>
<hr>
<div align="right"><small><i>&copy; Copyright Kevlin Henney, 2000, 2002</i></small></div>
</body>
</html> </html>
+273 -144
View File
@@ -1,149 +1,278 @@
// boost lexical_cast_test.cpp program -------------------------------------// // Unit test for boost::lexical_cast.
//
// See http://www.boost.org for most recent version including documentation. // See http://www.boost.org for most recent version, including documentation.
//
// what: lexical_cast custom keyword cast tests // Copyright Terje Slettebø and Kevlin Henney, 2003.
// who: contributed by Kevlin Henney
// when: October 2000
// where: tested with MSVC 6.0 and BCC 5.5
#include <boost/lexical_cast.hpp>
#include "test.hpp"
#include <complex>
#include <iostream>
#include <string>
using namespace boost;
using namespace std;
typedef test::test<const char *, void (*)()> test_case;
typedef const test_case * test_case_iterator;
extern const test_case_iterator begin, end;
int main()
{
test::tester<test_case_iterator> test_suite(begin, end);
return test_suite() ? EXIT_SUCCESS : EXIT_FAILURE;
}
void test_to_string()
{
test::check_equal(
lexical_cast<string>(2001), "2001",
"2001 -> \"2001\"");
test::check_equal(
lexical_cast<string>(2001.0), "2001",
"2001.0 ->\"2001\"");
test::check_equal(
lexical_cast<string>(complex<double>(2000,1)), "(2000,1)",
"complex<double>(2000,1) -> \"(2000,1)\"");
}
void test_to_int()
{
test::check_equal(
lexical_cast<int>("2001"), 2001,
"\"2001\" -> 2001");
test::check_equal(
lexical_cast<int>(" 2001"), 2001,
"\" 2001\" -> 2001");
test::check_equal(
lexical_cast<int>("2001 "), 2001,
"\"2001 \" -> 2001");
TEST_CHECK_THROW(
lexical_cast<int>("Two thousand and one"),
bad_lexical_cast,
"\"Two thousand and one\"");
TEST_CHECK_THROW(
lexical_cast<int>("2001: A Space Odyssey"),
bad_lexical_cast,
"\"2001: A Space Odyssey\"");
TEST_CHECK_THROW(
lexical_cast<int>(200.1),
bad_lexical_cast,
"200.1");
TEST_CHECK_THROW(
lexical_cast<int>("200e1"),
bad_lexical_cast,
"\"200e1\"");
}
void test_to_char()
{
test::check_equal(
lexical_cast<char>("2"), '2',
"\"2\" -> '2'");
test::check_equal(
lexical_cast<char>(" 2"), '2',
"\" 2\" -> '2'");
test::check_equal(
lexical_cast<char>("2 "), '2',
"\"2 \" -> '2'");
test::check_equal(
lexical_cast<char>(2), '2',
"2 -> '2'");
TEST_CHECK_THROW(
lexical_cast<char>("2001"),
bad_lexical_cast,
"\"2001\"");
TEST_CHECK_THROW(
lexical_cast<char>(2001),
bad_lexical_cast,
"2001");
}
void test_to_double()
{
test::check_equal(
lexical_cast<double>("1e6"), 1e6,
"\"1e6\" -> 1e6");
test::check_equal(
lexical_cast<double>("1e-2"), 1e-2,
"\"1e-2\" -> 1e-2");
}
void test_to_bool()
{
test::check_equal(
lexical_cast<bool>(1), true,
"1 -> true");
test::check_equal(
lexical_cast<bool>('0'), false,
"'0' -> false");
TEST_CHECK_THROW(
lexical_cast<bool>(2001),
bad_lexical_cast,
"2001");
TEST_CHECK_THROW(
lexical_cast<bool>(2),
bad_lexical_cast,
"2");
TEST_CHECK_THROW(
lexical_cast<bool>("true thousand and one"),
bad_lexical_cast,
"\"true thousand and one\"");
}
const test_case test_cases[] =
{
{ "lexical_cast<std::string>", test_to_string },
{ "lexical_cast<int>", test_to_int },
{ "lexical_cast<char>", test_to_char },
{ "lexical_cast<double>", test_to_double },
{ "lexical_cast<bool>", test_to_bool }
};
const test_case_iterator begin = test_cases;
const test_case_iterator end =
test_cases + (sizeof test_cases / sizeof *test_cases);
// Copyright Kevlin Henney, 2000. All rights reserved.
// //
// Permission to use, copy, modify, and distribute this software for any // Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and // purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives, and that no // permissions notice appear in all copies and derivatives.
// charge may be made for the software and its documentation except to cover
// cost of distribution.
// //
// This software is provided "as is" without express or implied warranty. // This software is provided "as is" without express or implied warranty.
#include <boost/config.hpp>
#if defined(__INTEL_COMPILER)
#pragma warning(disable: 193 383 488 981 1418 1419)
#elif defined(BOOST_MSVC)
#pragma warning(disable: 4097 4100 4121 4127 4146 4244 4245 4511 4512 4701 4800)
#endif
#include <boost/lexical_cast.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/included/unit_test_framework.hpp>
#if defined(BOOST_NO_STRINGSTREAM) || \
defined(BOOST_NO_STD_WSTRING) || \
defined(BOOST_NO_STD_LOCALE) || \
defined(BOOST_NO_CWCHAR) || \
defined(BOOST_MSVC) && (BOOST_MSVC <= 1200)
#define DISABLE_WIDE_CHAR_SUPPORT
#endif
using namespace boost;
void test_conversion_to_char();
void test_conversion_to_int();
void test_conversion_to_double();
void test_conversion_to_bool();
void test_conversion_to_string();
void test_conversion_to_pointer();
void test_conversion_from_wchar_t();
void test_conversion_to_wchar_t();
void test_conversion_from_wstring();
void test_conversion_to_wstring();
unit_test_framework::test_suite *init_unit_test_suite(int, char **)
{
unit_test_framework::test_suite *suite =
BOOST_TEST_SUITE("lexical_cast unit test");
suite->add(BOOST_TEST_CASE(test_conversion_to_char));
suite->add(BOOST_TEST_CASE(test_conversion_to_int));
suite->add(BOOST_TEST_CASE(test_conversion_to_double));
suite->add(BOOST_TEST_CASE(test_conversion_to_bool));
suite->add(BOOST_TEST_CASE(test_conversion_to_pointer));
suite->add(BOOST_TEST_CASE(test_conversion_to_string));
#ifndef DISABLE_WIDE_CHAR_SUPPORT
suite->add(BOOST_TEST_CASE(test_conversion_from_wchar_t));
suite->add(BOOST_TEST_CASE(test_conversion_to_wchar_t));
suite->add(BOOST_TEST_CASE(test_conversion_from_wstring));
suite->add(BOOST_TEST_CASE(test_conversion_to_wstring));
#endif
return suite;
}
void test_conversion_to_char()
{
BOOST_CHECK_EQUAL('A', lexical_cast<char>('A'));
BOOST_CHECK_EQUAL(' ', lexical_cast<char>(' '));
BOOST_CHECK_EQUAL('1', lexical_cast<char>(1));
BOOST_CHECK_EQUAL('0', lexical_cast<char>(0));
BOOST_CHECK_THROW(lexical_cast<char>(123), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL('1', lexical_cast<char>(1.0));
BOOST_CHECK_EQUAL('1', lexical_cast<char>(true));
BOOST_CHECK_EQUAL('0', lexical_cast<char>(false));
BOOST_CHECK_EQUAL('A', lexical_cast<char>("A"));
BOOST_CHECK_EQUAL(' ', lexical_cast<char>(" "));
BOOST_CHECK_THROW(lexical_cast<char>(""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<char>("Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL('A', lexical_cast<char>(std::string("A")));
BOOST_CHECK_EQUAL(' ', lexical_cast<char>(std::string(" ")));
BOOST_CHECK_THROW(
lexical_cast<char>(std::string("")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<char>(std::string("Test")), boost::bad_lexical_cast);
}
void test_conversion_to_int()
{
BOOST_CHECK_EQUAL(1,lexical_cast<int>('1'));
BOOST_CHECK_EQUAL(0,lexical_cast<int>('0'));
BOOST_CHECK_THROW(lexical_cast<int>('A'),boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(1,lexical_cast<int>(1));
BOOST_CHECK_EQUAL(
std::numeric_limits<int>::max(),
lexical_cast<int>(std::numeric_limits<int>::max()));
BOOST_CHECK_EQUAL(1,lexical_cast<int>(1.0));
BOOST_CHECK_THROW(lexical_cast<int>(1.23), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<int>(1e20), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(1, lexical_cast<int>(true));
BOOST_CHECK_EQUAL(0, lexical_cast<int>(false));
BOOST_CHECK_EQUAL(123, lexical_cast<int>("123"));
BOOST_CHECK_THROW(
lexical_cast<int>(" 123"), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<int>(""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<int>("Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(123, lexical_cast<int>("123"));
BOOST_CHECK_EQUAL(123,lexical_cast<int>(std::string("123")));
BOOST_CHECK_THROW(
lexical_cast<int>(std::string(" 123")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<int>(std::string("")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<int>(std::string("Test")), boost::bad_lexical_cast);
}
void test_conversion_to_double()
{
BOOST_CHECK_EQUAL(1.0, lexical_cast<double>('1'));
BOOST_CHECK_THROW(lexical_cast<double>('A'), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(1.0, lexical_cast<double>(1));
BOOST_CHECK_EQUAL(1.23, lexical_cast<double>(1.23));
BOOST_CHECK_CLOSE(
std::numeric_limits<double>::max() / 2,
lexical_cast<double>(std::numeric_limits<double>::max() / 2),
std::numeric_limits<double>::epsilon());
BOOST_CHECK_EQUAL(1.0, lexical_cast<double>(true));
BOOST_CHECK_EQUAL(0.0, lexical_cast<double>(false));
BOOST_CHECK_EQUAL(1.23, lexical_cast<double>("1.23"));
BOOST_CHECK_THROW(lexical_cast<double>(""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<double>("Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(1.23, lexical_cast<double>(std::string("1.23")));
BOOST_CHECK_THROW(
lexical_cast<double>(std::string("")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<double>(std::string("Test")), boost::bad_lexical_cast);
}
void test_conversion_to_bool()
{
BOOST_CHECK_EQUAL(true, lexical_cast<bool>('1'));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>('0'));
BOOST_CHECK_THROW(lexical_cast<bool>('A'), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(1));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(0));
BOOST_CHECK_THROW(lexical_cast<bool>(123), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(1.0));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(0.0));
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(true));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(false));
BOOST_CHECK_EQUAL(true, lexical_cast<bool>("1"));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>("0"));
BOOST_CHECK_THROW(lexical_cast<bool>(""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<bool>("Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(true, lexical_cast<bool>("1"));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>("0"));
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(std::string("1")));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(std::string("0")));
BOOST_CHECK_THROW(
lexical_cast<bool>(std::string("")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<bool>(std::string("Test")), boost::bad_lexical_cast);
}
void test_conversion_to_string()
{
BOOST_CHECK_EQUAL("A", lexical_cast<std::string>('A'));
BOOST_CHECK_EQUAL(" ", lexical_cast<std::string>(' '));
BOOST_CHECK_EQUAL("123", lexical_cast<std::string>(123));
BOOST_CHECK_EQUAL("1.23", lexical_cast<std::string>(1.23));
BOOST_CHECK_EQUAL("1.111111111", lexical_cast<std::string>(1.111111111));
BOOST_CHECK_EQUAL("1",lexical_cast<std::string>(true));
BOOST_CHECK_EQUAL("0",lexical_cast<std::string>(false));
BOOST_CHECK_EQUAL("Test", lexical_cast<std::string>("Test"));
BOOST_CHECK_EQUAL(" ", lexical_cast<std::string>(" "));
BOOST_CHECK_EQUAL("", lexical_cast<std::string>(""));
BOOST_CHECK_EQUAL("Test", lexical_cast<std::string>(std::string("Test")));
BOOST_CHECK_EQUAL(" ", lexical_cast<std::string>(std::string(" ")));
BOOST_CHECK_EQUAL("", lexical_cast<std::string>(std::string("")));
}
void test_conversion_to_pointer()
{
BOOST_CHECK_THROW(lexical_cast<char *>("Test"), boost::bad_lexical_cast);
#ifndef DISABLE_WIDE_CHAR_SUPPORT
BOOST_CHECK_THROW(lexical_cast<wchar_t *>("Test"), boost::bad_lexical_cast);
#endif
}
void test_conversion_from_wchar_t()
{
#ifndef DISABLE_WIDE_CHAR_SUPPORT
BOOST_CHECK_EQUAL(1, lexical_cast<int>(L'1'));
BOOST_CHECK_THROW(lexical_cast<int>(L'A'), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(123, lexical_cast<int>(L"123"));
BOOST_CHECK_THROW(lexical_cast<int>(L""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<int>(L"Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(1.0, lexical_cast<double>(L'1'));
BOOST_CHECK_THROW(lexical_cast<double>(L'A'), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(1.23, lexical_cast<double>(L"1.23"));
BOOST_CHECK_THROW(lexical_cast<double>(L""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<double>(L"Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(L'1'));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(L'0'));
BOOST_CHECK_THROW(lexical_cast<bool>(L'A'), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(L"1"));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(L"0"));
BOOST_CHECK_THROW(lexical_cast<bool>(L""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<bool>(L"Test"), boost::bad_lexical_cast);
#endif
}
void test_conversion_to_wchar_t()
{
#ifndef DISABLE_WIDE_CHAR_SUPPORT
BOOST_CHECK_EQUAL(L'1', lexical_cast<wchar_t>(1));
BOOST_CHECK_EQUAL(L'0', lexical_cast<wchar_t>(0));
BOOST_CHECK_THROW(lexical_cast<wchar_t>(123), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(L'1', lexical_cast<wchar_t>(1.0));
BOOST_CHECK_EQUAL(L'0', lexical_cast<wchar_t>(0.0));
BOOST_CHECK_EQUAL(L'1', lexical_cast<wchar_t>(true));
BOOST_CHECK_EQUAL(L'0', lexical_cast<wchar_t>(false));
BOOST_CHECK_EQUAL(L'A', lexical_cast<wchar_t>(L'A'));
BOOST_CHECK_EQUAL(L' ', lexical_cast<wchar_t>(L' '));
BOOST_CHECK_EQUAL(L'A', lexical_cast<wchar_t>(L"A"));
BOOST_CHECK_EQUAL(L' ', lexical_cast<wchar_t>(L" "));
BOOST_CHECK_THROW(lexical_cast<wchar_t>(L""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<wchar_t>(L"Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(L'A', lexical_cast<wchar_t>(std::wstring(L"A")));
BOOST_CHECK_EQUAL(L' ', lexical_cast<wchar_t>(std::wstring(L" ")));
BOOST_CHECK_THROW(
lexical_cast<wchar_t>(std::wstring(L"")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<wchar_t>(std::wstring(L"Test")), boost::bad_lexical_cast);
#endif
}
void test_conversion_from_wstring()
{
#ifndef DISABLE_WIDE_CHAR_SUPPORT
BOOST_CHECK_EQUAL(123, lexical_cast<int>(std::wstring(L"123")));
BOOST_CHECK_THROW(
lexical_cast<int>(std::wstring(L"")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<int>(std::wstring(L"Test")), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(std::wstring(L"1")));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(std::wstring(L"0")));
BOOST_CHECK_THROW(
lexical_cast<bool>(std::wstring(L"")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<bool>(std::wstring(L"Test")), boost::bad_lexical_cast);
#endif
}
void test_conversion_to_wstring()
{
#ifndef DISABLE_WIDE_CHAR_SUPPORT
BOOST_CHECK(L"123" == lexical_cast<std::wstring>(123));
BOOST_CHECK(L"1.23" == lexical_cast<std::wstring>(1.23));
BOOST_CHECK(L"1.111111111" == lexical_cast<std::wstring>(1.111111111));
BOOST_CHECK(L"1" == lexical_cast<std::wstring>(true));
BOOST_CHECK(L"0" == lexical_cast<std::wstring>(false));
BOOST_CHECK(L"A" == lexical_cast<std::wstring>(L'A'));
BOOST_CHECK(L" " == lexical_cast<std::wstring>(L' '));
BOOST_CHECK(L"Test" == lexical_cast<std::wstring>(L"Test"));
BOOST_CHECK(L" " == lexical_cast<std::wstring>(L" "));
BOOST_CHECK(L"" == lexical_cast<std::wstring>(L""));
BOOST_CHECK(L"Test" == lexical_cast<std::wstring>(std::wstring(L"Test")));
BOOST_CHECK(L" " == lexical_cast<std::wstring>(std::wstring(L" ")));
BOOST_CHECK(L"" == lexical_cast<std::wstring>(std::wstring(L"")));
#endif
}