So typically if I wanted to insert locale appropriate separators in some number, foo
, I'd do something like this:
ostringstream out;
out.imbue(locale("en-US"));
out << foo;
Then I could just use out.str()
as the separated string: http://coliru.stacked-crooked.com/a/054e927de25b5ad0
Unfortunately I've been asked not to use stringstreams
in my current project. Is there any other way I can accomplish this? Ideally a locale dependent way?
So this answer is the C++ distillation of Jerry Coffin's answer to this question: Cross Platform Support for sprintf's Format '-Flag
template <typename T>
enable_if_t<is_integral_v<remove_reference_t<T>>, string> poscommafmt(const T N, const numpunct<char>& fmt_info) {
const auto group = fmt_info.grouping();
auto posn = cbegin(group);
auto divisor = static_cast<T>(pow(10.0F, static_cast<int>(*posn)));
auto quotient = div(N, divisor);
auto result = to_string(quotient.rem);
while(quotient.quot > 0) {
if(next(posn) != cend(group)) {
divisor = static_cast<T>(pow(10.0F, static_cast<int>(*++posn)));
}
quotient = div(quotient.quot, divisor);
result = to_string(quotient.rem) + fmt_info.thousands_sep() + result;
}
return result;
}
template <typename T>
enable_if_t<is_integral_v<remove_reference_t<T>>, string> commafmt(const T N, const numpunct<char>& fmt_info) {
return N < 0 ? '-' + poscommafmt(-N, fmt_info) : poscommafmt(N, fmt_info);
}
Naturally this suffers from the identical 2's compliment negation issue.
This certainly benefits from C++'s string
memory management, but also from the ability to pass in a specific numpunct<char>
which need not be the current locale. For example whether or not cout.getloc() == locale("en-US")
you can call: commafmt(foo, use_facet<numpunct<char>>(locale("en-US")))