How can I set the decimal separator to be a comma?

21,941

Solution 1

You should use basic_ios::imbue to set the preferred locale.

Take a look here: http://www.cplusplus.com/reference/ios/ios_base/imbue/

Locales allow you to use the preferred way by the user, so if a computer in Italy uses comma to separate decimal digits, in the US the dot is still used. Using locales is a Good Practice.

But if you want to explicitly force the use of the comma, take a look here: http://www.cplusplus.com/reference/locale/numpunct/decimal_point/

Here a small example I just made with g++ which enforces the char ',' (passing the separator as template argument is just for fun, not really necessary)

#include <iostream>
#include <locale>

template <class charT, charT sep>
class punct_facet: public std::numpunct<charT> {
protected:
    charT do_decimal_point() const { return sep; }
};

int main(int argc, char **argv) {
    std::cout.imbue(std::locale(std::cout.getloc(), new punct_facet<char, ','>));
    std::cout << "My age is " << 3.1415 << " lightyears.\n";
}

Note that using cout.getloc() I'm overriding just a single facet in the currently set locale, that is, in the current locale settings of cout, I'm changing only how the punctuation is done.

do_decimal_point is a virtual function of std::numpunct that you can redefine to provide your custom separator. This virtual function will be used by numpunct::decimal_point when printing your number.

Solution 2

As @AkiRoss said, you need to use locales. In general, in any program you write, one of the very first actions in main should be to set the global locale to the users choice, by doing something like:

std::locale::global( std::locale( "" ) );

This should be systematic, in every program which interacts with a human user. All files opened after this will automatically be imbued with the correct locale.

Alternatively, you can explicitly specify the locale you want to use:

std::locale::global( std::locale( locale_name ) );

The problem with this is that there is no standard for locale names. Something like "it_IT.UTF-8" corresponds to the Posix standard, and is used on the Internet; Windows has traditionally used a different format (although recent Windows do seem to accept this format as well).

Which leaves std::cin, std::cout and std::cerr. These are opened before you enter main, and so must be imbued with the new locale. (To obtain a copy of the current global locale, use the default constructor of std::locale.)

Finally, if you're opening any binary files, be aware that they also will be imbued with the global locale. Which may do code translation. In such cases, you should imbue them explicitly with std::locale::classic(), or create a new locale by merging the codecvt facet of std::locale::classic() with the other facets of the global locale. (std::locale has special functions and constructors for this.)

Share:
21,941
Ralph Tandetzky
Author by

Ralph Tandetzky

I'm a professional C++ developer and a hobby D developer.

Updated on November 08, 2020

Comments

  • Ralph Tandetzky
    Ralph Tandetzky over 3 years

    I would like to read and write pi as 3,141592 instead of 3.141592, as using the comma is common in many European countries. How can I accomplish this with iostreams? In other words

    cout << 3.141592;
    

    should print

    3,141592
    

    to standard output.