Locale invariant guarantee of boost::lexical_cast<>
Asked Answered
G

2

8

I'm using boost::lexical_cast<std::string>(double) for converting doubles to string, generating JSON serialized byte stream, that is (on remote side) parsed by .NET.

I'm able to force the .NET to use InvariantCulture for parsing, thereby returning predictable result on every possible language.

However, I was not able to find this guarantee in boost::lexical_cast documentation. I tried it a little bit, and it works the same way for different locales set. But, I cannot be sure only from few tests, am I missing something in the documentation, or this cannot be guaranted at all, and I have to use something else?

EDIT: I've found an issue.

std::locale::global(std::locale("Czech")); 
std::cout << boost::lexical_cast<std::string>(0.15784465) << std::endl;

returns 0,15784465, and that is undesired. Can I force the boost::lexical_cast<> not to be aware of locales?

Googolplex answered 24/9, 2013 at 11:31 Comment(2)
Possible duplicate of Locale-invariant string processing with strtod strtof atof printf?Yoko
consider using sqlite printf which is locale invariant and can do what you want. all the c++ conversion functions including in various other libraries depend on locale.Yoko
F
8

Can I force the boost::lexical_cast<> not to be aware of locales?

No, I don't think that is possible. The best you can do is call

std::locale::global(std::locale::classic());

to set the global locale to the "C" locale as boost::lexical_cast relies on the global locale. However, the problem is if somewhere else in the code the global locale is set to something else before calling boost::lexical_cast, then you still have the same problem. Therefore, a robust solution would be imbue a stringstream like so, and you can be always sure that this works:

std::ostringstream oss;
oss.imbue(std::locale::classic());
oss.precision(std::numeric_limits<double>::digits10);
oss << 0.15784465;
Fustian answered 24/9, 2013 at 12:22 Comment(2)
Fundamentally, the problem is that the C++ locale is not a thread-local, RAII-respecting property.Outoftheway
You saved my from Archive exception in several locale Windows. Thank you so much!Immersed
B
3

A better solution to this problem is to use a boost::locale instead of a std::locale as the globale locale. From the documentation:

Setting the global locale has bad side effects... it affects even printf and libraries like boost::lexical_cast giving incorrect or unexpected formatting. In fact many third-party libraries are broken in such a situation. Unlike the standard localization library, Boost.Locale never changes the basic number formatting, even when it uses std based localization backends, so by default, numbers are always formatted using C-style locale. Localized number formatting requires specific flags.

Boost locale requires you to specify explicitly when you want numeric formatting to be locale aware, which is more consistent with recent library decisions like std::money_put.

Bobseine answered 27/8, 2015 at 7:20 Comment(2)
How would you use this with boost::lexical_cast?Undaunted
boost::lexical_cast makes use of the global locale. the boost::locale library generates locales with improved numeric formatting behavior (among other improvements). So simply set the the globale locale to a boost locale, and it boost::lexical_cast will adopt the behavior automatically. If that's not clear let me know, I'll make an example.Bobseine

© 2022 - 2024 — McMap. All rights reserved.