Предположим, наше приложение работает с текстовым представлением чисел, и в этом представлении «десятичная точка» должна быть на самом деле запятой. В C++ достаточно обширные возможности манипуляции с локальными языковыми особенностями (т.н. locales), грех ими не воспользоваться.
Не вдаваясь в подробности, скажу, что за представление чисел отвечает «аспект» (facet) std::numpunct. Для модификации представления десятичной точки достаточно переопределить виртуальный метод do_decimal_point()
Дальнейшее использование этого аспекта зависит от характера работы приложения. Скажем, при однократном выводе достаточно «внедрить» (imbue) этот аспект в локаль потока:
Беспокоиться об удалении (delete) не следует, классы аспектов ведут подсчет ссылок (reference counting) и удаляются когда не остаётся локалей, ссылающихся на них, в данном случае по выходу из функции. Если эта функция вызывается многократно, имеет смысл создать новую локаль отдельно и «внедрять» её в поток перед началом вывода.
Для повсеместной смены интерпретации чисел, следует заменить «глобальную» локаль:
Замечу, что при этом представление чисел меняется не только при выводе, но также и при вводе, т.е. operator>> при вводе чисел будет рассматривать символ запятой как «десятичную точку». По этой причине следует быть осторожным, манипулируя глобальной локалью.
В заключение стоит упомянуть об ещё одном методе аспекта numpunct, позволяющем группировать в числах разряды, do_thousand_grouping:
По материалам драфта ISO/IEC FDIS 14882 N3290 от 11 апреля 2011 года,
разделы [22.3] и [22.4.3]. См. также о языковых и культурных особенностях.
Не вдаваясь в подробности, скажу, что за представление чисел отвечает «аспект» (facet) std::numpunct. Для модификации представления десятичной точки достаточно переопределить виртуальный метод do_decimal_point()
#include <locale><br/>
<br/>
struct num_comma : std::numpunct<char><br/>
{<br/>
char do_decimal_point () const { return ','; }<br/>
};
Дальнейшее использование этого аспекта зависит от характера работы приложения. Скажем, при однократном выводе достаточно «внедрить» (imbue) этот аспект в локаль потока:
void print_data (std::ostream& out, double x)<br/>
{<br/>
std::locale old_loc = out.imbue (std::locale (out.getloc(), new num_comma));<br/>
out << x;<br/>
// замечу, что такой подход не является exception-safe -- любое<br/>
// исключение в теле функции оставит поток с внедрённой изменённой<br/>
// локалью. следует создать класс-обёртку, в конструкторе и<br/>
// деструкторе которого производить внедрение и его отмену.<br/>
out.imbue (old_loc);<br/>
}
Беспокоиться об удалении (delete) не следует, классы аспектов ведут подсчет ссылок (reference counting) и удаляются когда не остаётся локалей, ссылающихся на них, в данном случае по выходу из функции. Если эта функция вызывается многократно, имеет смысл создать новую локаль отдельно и «внедрять» её в поток перед началом вывода.
// создаём копию глобальной локали со своим "аспектом"<br/>
std::locale comma_locale (std::locale(), new num_comma);<br/>
out.imbue (comma_locale);<br/>
// ...<br/>
out << some_number;
Для повсеместной смены интерпретации чисел, следует заменить «глобальную» локаль:
// где-то в районе инициализации приложения, скажем, в начале main()<br/>
std::locale comma_loc (std::locale(), new num_comma);<br/>
std::locale::global (comma_loc);<br/>
<br/>
// стандартные потоки уже инициализированы локалью по умолчанию,<br/>
// поэтому если предполагается работа с ними, их надо модифицировать:<br/>
std::cout.imbue (comma_loc);<br/>
std::cin.imbue (comma_loc);<br/>
<br/>
// все вновь создаваемые потоки (std::fstream, std::stringstream) будут<br/>
// сами "подхватывать" нашу модифицированную глобальную локаль.<br/>
Замечу, что при этом представление чисел меняется не только при выводе, но также и при вводе, т.е. operator>> при вводе чисел будет рассматривать символ запятой как «десятичную точку». По этой причине следует быть осторожным, манипулируя глобальной локалью.
В заключение стоит упомянуть об ещё одном методе аспекта numpunct, позволяющем группировать в числах разряды, do_thousand_grouping:
struct num_sep : std::numpunct<char><br/>
{<br/>
// разделитель разрядов<br/>
char do_thousands_sep () const { return '\''; }<br/>
// группировать разряды по 3<br/>
std::string do_grouping () const { return "\003"; }<br/>
};<br/>
<br/>
std::cout.imbue (std::locale (std::cout.getloc(), new num_sep));<br/>
std::cout << 12345678 << std::endl;<br/>
// выведет 12'345'678<br/>
По материалам драфта ISO/IEC FDIS 14882 N3290 от 11 апреля 2011 года,
разделы [22.3] и [22.4.3]. См. также о языковых и культурных особенностях.