boost::locale::generator gen;
std::locale loc = gen("de_DE.UTF-8");
std::locale::global(loc);
std::string s = "3,14";
double d = boost::lexical_cast<double>(s);
std::cout << d << std::endl;
Why does this code throw an exception? Boost Locale does not affect lexical cast?
I want to use a comma as a separator, not a period.
Boost Locale doesn't apply to any number. You have to tell it using IO manipulators. E.g.:
#include <boost/lexical_cast.hpp>
#include <boost/locale.hpp>
#include <iostream>
namespace as = boost::locale::as;
int main() {
boost::locale::generator gen;
auto de = gen("de_DE.utf8");
// std::locale::global(de);
std::cout.imbue(de);
std::cin.imbue(de);
std::cout << 134.45 << std::endl;
std::cout << as::number << 134.45 << std::endl;
std::cout << as::currency << 134.45 << std::endl;
}
Prints
134.45
134,45
134,45 €
So, it stands to reason that the following will work: Live On Coliru
if (double punkt; is("123.45") >> punkt)
std::cout << "Punkt " << punkt << "\n";
else std::cout << "Punkt failed\n";
if (double komma; is("123,45") >> komma)
std::cout << "Komma " << komma << " (OOPS!)\n";
else std::cout << "Komma failed\n";
if (double nummer; is("123,45") >> as::number >> nummer)
std::cout << "Nummer " << nummer << "\n";
else std::cout << "Nummer failed\n";
Prints (note the OOPS
case):
Punkt 123,45 €
Komma 123,00 € (OOPS!)
Nummer 123,45 €
Even if you do set the global locale, lexical_cast
will not accept the manipulators. But Boost Convert does:
The original hope was to see boost::lexical_cast extended to be applicable to a wider range of deployment scenarios. However, after discussions with Kevlin Henney (the boost::lexical_cast author) and in the Boost Developers forum it was collectively decided that the desired extensions were not compatible with the original design and the idea of what boost::lexical_cast embodied and, therefore, a new component with richer interface and functionality was needed. That decision resulted in the development of Boost.Convert described in this document.
The 30s introduction I'd give: Live On Coliru
#include <boost/convert.hpp>
#include <boost/convert/stream.hpp>
#include <boost/locale.hpp>
#include <iostream>
namespace cnv = boost::cnv;
int main() {
boost::locale::generator gen;
std::locale::global(gen("de_DE.utf8"));
cnv::cstream cnv;
cnv(boost::locale::as::number);
auto from_string = cnv::apply<double>(std::ref(cnv));
auto to_string = cnv::apply<std::string>(std::ref(cnv));
std::cout << "Parsed " << from_string("123,45") << "\n";
std::cout << "Formatted " << to_string(123.45) << "\n";
}
Of course, it is quite convenient to have lexical_cast Just Work(TM). You might introduce a light-weight wrapper type:
#include <boost/lexical_cast.hpp>
#include <boost/locale.hpp>
#include <iostream>
namespace as = boost::locale::as;
struct Number {
double value_;
Number(double init = {}) : value_(init) {}
operator double() const { return value_; }
friend std::istream& operator>>(std::istream& is, Number& num) {
return is >> as::number >> num.value_ >> as::posix;
}
friend std::ostream& operator<<(std::ostream& os, Number const& num) {
return os << as::number << num.value_ << as::posix;
}
};
int main() {
boost::locale::generator gen;
std::locale::global(gen("de_DE.utf8"));
std::cout << "Formatted: " << boost::lexical_cast<std::string>(Number{234.56}) << "\n";
double parsed = boost::lexical_cast<Number>("345,67");
std::cout << "Parsed: " << parsed << "\n";
}
Prints
Formatted: 234,56
Parsed: 345.67
Note that you might even evolve Number
to be a vocabulary type, so you won't have to wrap it for conversions.