Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Currency format in C++

Tags:

c++

c++11

I would like to format prices in C++

I can use std::put_money but the problem is that my number format locale is different from my currency locale.

Say I want to format a price in GBP in French, if I set the locale to French, I get a euro sign. I need the decimal in the user's locale and the currency in the price locale.

I can do that in Java with NumberFormat coming from the decimal locale and then setting the currency I want on it.

Can this be done in C++?

like image 394
stephane k. Avatar asked Jul 23 '18 14:07

stephane k.


1 Answers

You can create your own moneypunct facet, inheriting from std::moneypunct, and construct a locale using it. Here's such facet you can construct from two locale names. One is responsible for the currency symbol and the other is for everything else.

template <class CharT, bool International = false>
class my_moneypunct;

template <class CharT, bool International = false>
class my_moneypunct_byname : public std::moneypunct_byname<CharT, International>
{
  friend class my_moneypunct<CharT, International>;
  using std::moneypunct_byname<CharT, International>::moneypunct_byname;
};

template <class CharT, bool International>
class my_moneypunct : public std::moneypunct_byname<CharT, International>
{
    my_moneypunct_byname<CharT, International> other_moneypunct;
    public:
    explicit my_moneypunct(const char* myName, const char* otherName, std::size_t refs = 0) :
        std::moneypunct_byname<CharT, International>(myName, refs), other_moneypunct(otherName, refs) {}
    typename std::moneypunct_byname<CharT, International>::string_type do_curr_symbol() const override {
        return other_moneypunct.do_curr_symbol();
    }
    virtual ~my_moneypunct() = default;
};

You can use it this way:

std::moneypunct<char>* mp = new_moneypunct<char>("en_GB.UTF-8", "fr_FR.UTF-8");
// or std::moneypunct<char>* mp = new_moneypunct<char>("fr_FR.UTF-8", "en_GB.UTF-8");
std::locale newloc(std::locale(), mp);
std::cout.imbue(newloc);
std::cout << std::showbase << std::put_money("1234567");
// prints '€12,345.67' or '12 345,67 £'

Note this is not tested for memory leaks.

You also can, instead of inheriting std::moneypunct_byname, inherit just std::moneypunct and forward every overridable method to different moneypunct facets you fetch from several locales using std::use_facet. Or hard code your currency symbol, or any other way you like.

like image 120
n. 1.8e9-where's-my-share m. Avatar answered Oct 01 '22 02:10

n. 1.8e9-where's-my-share m.