std::lexical_cast - is there such a thing?
Only partially.
C++11 <string>
has std::to_string
for the built-in types:
[n3290: 21.5/7]:
string to_string(int val);
string to_string(unsigned val);
string to_string(long val);
string to_string(unsigned long val);
string to_string(long long val);
string to_string(unsigned long long val);
string to_string(float val);
string to_string(double val);
string to_string(long double val);
Returns: Each function returns a
string
object holding the
character representation of the value of its argument that would
be generated by callingsprintf(buf, fmt, val)
with a format
specifier of"%d"
,"%u"
,"%ld"
,"%lu"
,"%lld"
,"%llu"
,
"%f"
,"%f"
, or"%Lf"
, respectively, wherebuf
designates
an internal character buffer of sufficient size.
There are also the following that go the other way around:
[n3290: 21.5/1, 21.5/4]:
int stoi(const string& str, size_t *idx = 0, int base = 10);
long stol(const string& str, size_t *idx = 0, int base = 10);
unsigned long stoul(const string& str, size_t *idx = 0, int base = 10);
long long stoll(const string& str, size_t *idx = 0, int base = 10);
unsigned long long stoull(const string& str, size_t *idx = 0, int base = 10);
float stof(const string& str, size_t *idx = 0);
double stod(const string& str, size_t *idx = 0);
long double stold(const string& str, size_t *idx = 0);
However, there's nothing generic that you can use (at least not until TR2, maybe!), and nothing at all in C++03.
Boost's lexical_cast From double to string Precision
The boost code ends up here:
bool shl_real_type(double val, char* begin) {
using namespace std;
finish = start +
#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)
sprintf_s(begin, CharacterBufferSize,
#else
sprintf(begin,
#endif
"%.*g", static_cast<int>(boost::detail::lcast_get_precision<double>()), val);
return finish > start;
}
You're in luck since the precision is USUALLY compile-time constant (unless boost configures BOOST_LCAST_NO_COMPILE_TIME_PRECISION
).
Simplifying a bit and allowing for conforming, modern standard libraries:
Mimicking Boost Lexicalcast
#include <cstdio>
#include <limits>
#include <string>
namespace {
template <class T> struct lcast_precision {
typedef std::numeric_limits<T> limits;
static constexpr bool use_default_precision = !limits::is_specialized || limits::is_exact;
static constexpr bool is_specialized_bin = !use_default_precision && limits::radix == 2 && limits::digits > 0;
static constexpr bool is_specialized_dec = !use_default_precision && limits::radix == 10 && limits::digits10 > 0;
static constexpr unsigned int precision_dec = limits::digits10 + 1U;
static constexpr unsigned long precision_bin = 2UL + limits::digits * 30103UL / 100000UL;
static constexpr unsigned value = is_specialized_bin
? precision_bin
: is_specialized_dec? precision_dec : 6;
};
std::string mimicked(double v) {
constexpr int prec = static_cast<int>(lcast_precision<double>::value);
std::string buf(prec+10, ' ');
buf.resize(sprintf(&buf[0], "%.*g", prec, v));
return buf;
}
}
Regression Tests
To compare the results and check the assumptions:
Live On Coliru
#include <cstdio>
#include <limits>
#include <string>
namespace {
template <class T> struct lcast_precision {
typedef std::numeric_limits<T> limits;
static constexpr bool use_default_precision = !limits::is_specialized || limits::is_exact;
static constexpr bool is_specialized_bin = !use_default_precision && limits::radix == 2 && limits::digits > 0;
static constexpr bool is_specialized_dec = !use_default_precision && limits::radix == 10 && limits::digits10 > 0;
static constexpr unsigned int precision_dec = limits::digits10 + 1U;
static constexpr unsigned long precision_bin = 2UL + limits::digits * 30103UL / 100000UL;
static constexpr unsigned value = is_specialized_bin
? precision_bin
: is_specialized_dec? precision_dec : 6;
};
std::string mimicked(double v) {
constexpr int prec = static_cast<int>(lcast_precision<double>::value);
std::string buf(prec+10, ' ');
buf.resize(sprintf(&buf[0], "%.*g", prec, v));
return buf;
}
}
#include <cmath>
#include <iomanip>
#include <iostream>
#include <string>
#include <boost/lexical_cast.hpp>
#ifdef BOOST_LCAST_NO_COMPILE_TIME_PRECISION
#error BOOM
#endif
#define TEST(x) \
do { \
std::cout << std::setw(45) << #x << ":\t" << (x) << "\n"; \
} while (0)
std::string use_sprintf(double v) {
std::string buf(32, ' ');
buf.resize(std::sprintf(&buf[0], "%f", v));
return buf;
}
void tests() {
for (double v : {
std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::infinity(),
-std::numeric_limits<double>::infinity(),
0.0,
-0.0,
std::numeric_limits<double>::epsilon(),
M_PI })
{
TEST(v);
TEST(std::to_string(v));
TEST(use_sprintf(v));
TEST(boost::lexical_cast<std::string>(v));
TEST(mimicked(v));
assert(mimicked(v) == boost::lexical_cast<std::string>(v));
}
}
static std::locale DE("de_DE.utf8");
int main() {
tests();
std::cout << "==== imbue std::cout\n";
std::cout.imbue(DE);
tests();
std::cout << "==== override global locale\n";
std::locale::global(DE);
tests();
}
Prints
v: nan
std::to_string(v): nan
use_sprintf(v): nan
boost::lexical_cast<std::string>(v): nan
mimicked(v): nan
v: inf
std::to_string(v): inf
use_sprintf(v): inf
boost::lexical_cast<std::string>(v): inf
mimicked(v): inf
v: -inf
std::to_string(v): -inf
use_sprintf(v): -inf
boost::lexical_cast<std::string>(v): -inf
mimicked(v): -inf
v: 0
std::to_string(v): 0.000000
use_sprintf(v): 0.000000
boost::lexical_cast<std::string>(v): 0
mimicked(v): 0
v: -0
std::to_string(v): -0.000000
use_sprintf(v): -0.000000
boost::lexical_cast<std::string>(v): -0
mimicked(v): -0
v: 2.22045e-16
std::to_string(v): 0.000000
use_sprintf(v): 0.000000
boost::lexical_cast<std::string>(v): 2.2204460492503131e-16
mimicked(v): 2.2204460492503131e-16
v: 3.14159
std::to_string(v): 3.141593
use_sprintf(v): 3.141593
boost::lexical_cast<std::string>(v): 3.1415926535897931
mimicked(v): 3.1415926535897931
==== imbue std::cout
v: nan
std::to_string(v): nan
use_sprintf(v): nan
boost::lexical_cast<std::string>(v): nan
mimicked(v): nan
v: inf
std::to_string(v): inf
use_sprintf(v): inf
boost::lexical_cast<std::string>(v): inf
mimicked(v): inf
v: -inf
std::to_string(v): -inf
use_sprintf(v): -inf
boost::lexical_cast<std::string>(v): -inf
mimicked(v): -inf
v: 0
std::to_string(v): 0.000000
use_sprintf(v): 0.000000
boost::lexical_cast<std::string>(v): 0
mimicked(v): 0
v: -0
std::to_string(v): -0.000000
use_sprintf(v): -0.000000
boost::lexical_cast<std::string>(v): -0
mimicked(v): -0
v: 2,22045e-16
std::to_string(v): 0.000000
use_sprintf(v): 0.000000
boost::lexical_cast<std::string>(v): 2.2204460492503131e-16
mimicked(v): 2.2204460492503131e-16
v: 3,14159
std::to_string(v): 3.141593
use_sprintf(v): 3.141593
boost::lexical_cast<std::string>(v): 3.1415926535897931
mimicked(v): 3.1415926535897931
==== override global locale
v: nan
std::to_string(v): nan
use_sprintf(v): nan
boost::lexical_cast<std::string>(v): nan
mimicked(v): nan
v: inf
std::to_string(v): inf
use_sprintf(v): inf
boost::lexical_cast<std::string>(v): inf
mimicked(v): inf
v: -inf
std::to_string(v): -inf
use_sprintf(v): -inf
boost::lexical_cast<std::string>(v): -inf
mimicked(v): -inf
v: 0
std::to_string(v): 0,000000
use_sprintf(v): 0,000000
boost::lexical_cast<std::string>(v): 0
mimicked(v): 0
v: -0
std::to_string(v): -0,000000
use_sprintf(v): -0,000000
boost::lexical_cast<std::string>(v): -0
mimicked(v): -0
v: 2,22045e-16
std::to_string(v): 0,000000
use_sprintf(v): 0,000000
boost::lexical_cast<std::string>(v): 2,2204460492503131e-16
mimicked(v): 2,2204460492503131e-16
v: 3,14159
std::to_string(v): 3,141593
use_sprintf(v): 3,141593
boost::lexical_cast<std::string>(v): 3,1415926535897931
mimicked(v): 3,1415926535897931
Note that mimicked
and boost::lexical_cast<std::string>(double)
result in exactly the same output each time.
Extended boost::lexical_cast for other class datatypes
You can define a specialization of boost::lexical_cast for the types that you want to convert.
Toy example:
typedef struct { int x; int y; } Point;
namespace boost {
template<>
std::string lexical_cast(const Point& arg) { return "2,3"; }
}
int main () {
std::cout << boost::lexical_cast<std::string>(Point ()) << std::endl;
}
prints 2,3
.
Going from a string to a point requires a bit more work, but you can see how to do it.
Unexpected results from boost::lexical_castint with boost::iterator_range
The short answer is number 2 from your list, misuse of iterator_range
- specifically you're using it without explicitly including the proper header for it.
Adding this:
#include <boost/range/iterator_range.hpp>
will make it behave as you expect.
The iterator_range
and related functionality is split into two headers, iterator_range_core.hpp
and iterator_range_io.hpp
. The first one contains the class definition, the second one contains, among other things, the operator<<
overload which makes it streamable and so usable by lexical_cast
(usable in the sense that it will actually work as you expect).
Because you didn't included the proper header, you should normally get a compiler error, but in this case you're not getting it because lexical_cast.hpp
includes the first of those two headers, iterator_range_core.hpp
. This makes everything build fine, but it doesn't get the operator<<
from the second header. Without that overload, when lexical_cast
writes the range to the stream to perform the conversion, the best overload it finds is the one taking a bool
parameter (because iterator_range
has a default conversion to bool
). That's why you're seeing that 1
, because it's actually writing true
to the underlying conversion stream.
You can test this easily with something like this:
auto someRange = boost::make_iterator_range(first, last);
std::cout << std::boolalpha<< someRange;
Without #include <boost/range/iterator_range.hpp>
this will print true
, with that include
it will print your string (80).
Is boost::lexical_cast redundant with c++11 stoi, stof and family?
boost::lexical_cast
- handles more kinds of conversion, including iterator pairs, arrays, C strings, etc.
- offers the same generic interface (
sto*
have different names for different types) - is locale-sensitive (
sto*
/to_string
are only in part, e.g.lexical_cast
can process thousands separators, whilestoul
usually doesn't)
C++ boost lexical_cast with template?
CString does not have any operator<<
Consider using std::string
What overhead is there in performing an identity boost::lexical_cast?
Since the documentation doesn't offer anything on this topic, I dug into the lexical_cast
source (1.51.0) and found that it does some compile-time checking on the types and decides a specific "caster class" that does the conversion. In case source and target are the same, this "caster class" will simply return the input.
Pseudo-codified and simplified from source (boost/lexical_cast.hpp:2268
):
template <typename Target, typename Source>
Target lexical_cast(const Source &arg)
{
static if( is_character_type_to_character_type<Target, src> ||
is_char_array_to_stdstring<Target, src> ||
is_same_and_stdstring<Target, src> )
// ^-- optimization for std::string to std::string and similar stuff
{
return arg;
}
else
{
/* some complicated stuff */
}
}
I can't directly see any optimizations for other identity casts, though, and looking through the normally selected lexical_cast_do_cast
"caster class" is making my head hurt. :(
Adding type for conversion by boost::lexical_cast (segfault)
It sounds like the crash is due to a stack overflow. I think your operator>>
is calling itself, by implicitly converting foo.str
back into a Foo
.
Try removing the implicit conversion by making that constructor explicit:
explicit Foo(const std::string& str) noexcept
: str(str)
{
}
Is there a boost lexical_cast equivalent of C# TryParse?
If you can use boost, then you could use boost::conversion::try_lexical_convert
:
#include <boost/lexical_cast/try_lexical_convert.hpp>
std::string str("1.2");
double res;
if(boost::conversion::try_lexical_convert<double>(str, res)){
//everything normal
}
else{
//we got a problem
}
Related Topics
Why Sizeof Int Is Wrong, While Sizeof(Int) Is Right
Is There a Compact Equivalent to Python Range() in C++/Stl
Do I Have to Bind a Udp Socket in My Client Program to Receive Data? (I Always Get Wsaeinval)
Boost-Python How to Pass a C++ Class Instance to a Python Class
Shared_Ptr<> Is to Weak_Ptr<> as Unique_Ptr<> Is To... What
Who Defines C Operator Precedence and Associativity
Why Is Rvo Disallowed When Returning a Parameter
How to Execute Another Exe from a C++ Program in Windows
Why Does the Main Function Work with No Return Value
Static VS Non-Static Variables in Namespace
Show Two Digits After Decimal Point in C++
Project Error: Unknown Module(S) in Qt: Webkitwidgets
Uses for Anonymous Namespaces in Header Files
C++ [Windows] Path to the Folder Where the Executable Is Located
What Could C/C++ "Lose" If They Defined a Standard Abi
Is a Linked-List Implementation Without Using Pointers Possible or Not