На этом шаге мы закончим изучение особенностей использования локальных контекстов.
Как правило, программы не определяют свои локальные контексты, кроме случаев, когда чтение и запись данных производятся в фиксированном формате. Вместо этого локальный контекст определяется по значению переменной окружения LANG. Имя локального контекста также может вводиться из других источников, как показано в следующем примере:
//--------------------------------------------------------------------------- #include <vcl.h> #include <iostream> #include <locale> #include <string> #include <cstdlib> #include <conio.h> //необходимо для getch() #pragma hdrstop //--------------------------------------------------------------------------- #pragma argsused using namespace std; std::string ToRus(const std::string &in) { char *buff = new char [in.length()+1]; CharToOem(in.c_str(),buff); std::string out(buff); delete [] buff; return out; } int main (int argc, char* argv[]) { // Создание локального контекста по умолчанию // в зависимости от состояния переменной окружения locale langLocale(""); // Присваивание локального контекста стандартному каналу вывода cout.imbue(langLocale); // Обработка имени локального контекста bool isGerman; if (langLocale.name() == "de_DE" || langLocale.name() == "de" || langLocale.name() == "german") { isGerman = true; } else { isGerman = false; } // Чтение локального контекста для ввода if (isGerman) { cout << "Sprachumgebung fuer Eingaben: "; } else { cout << ToRus("Задайте локальный контекст: "); } string s; cin >> s; if (!cin) { if (isGerman) { cerr << "FEHLER beim Einlesen der Sprachumgebung" << endl; } else { cerr << ToRus("Ошибка при задании локального контекста") << endl; } return EXIT_FAILURE; } locale cinLocale(s.c_str()); // Присваивание локального контекста стандартному каналу ввода cin.imbue(cinLocale); // Чтение и запись вещественных чисел в цикле double value; while (cin >> value) { cout << value << endl; } getch(); return 0; } //---------------------------------------------------------------------------
Результат работы программы приведен на рисунке 1.
Рис.1. Результат работы приложения
В этом примере следующая команда создает объект класса locale:
locale langLocale("");
Пустая строка вместо имени локального контекста имеет особый смысл: она обозначает локальный контекст по умолчанию для окружения пользователя (обычно определяется переменной окружения LANG). Этот локальный контекст связывается со стандартным входным потоком данных командой:
cout.imbue(langLocale);
Показанное ниже выражение возвращает имя локального контекста по умолчанию в виде объекта типа string:
langLocale.name()
Следующий фрагмент конструирует локальный контекст по имени, прочитанному из стандартного входного потока данных:
string s; cin >> s; . . . . . . locale cinLocale(s.c_str());
Для этого из стандартного входного потока данных читается слово, передаваемое в аргументе конструктора. Если попытка чтения завершается неудачей, во входном потоке данных устанавливается флаг ios_base::failbit. Программа проверяет и обрабатывает эту ситуацию:
if (!cin) { if (isGerman) { cerr << "FEHLER beim Einlesen der Sprachumgebung" << endl; } else { cerr << "ERROR while reading the locale" << endl; } return EXIT_FAILURE;
Если содержимое строки не позволяет сконструировать локальный контекст, также генерируется исключение runtime_error.
Если программист хочет соблюдать национальные стандарты, он должен задействовать соответствующие объекты локальных контекстов. Статическая функция global() класса locale устанавливает новый глобальный объект локального контекста. Этот объект будет использоваться по умолчанию функциями, которым при вызове может передаваться необязательный аргумент с локальным контекстом. Если объект локального контекста, назначенный функцией global(), обладает именем, вызов global() также обеспечивает правильную реакцию со стороны функций С с поддержкой локальных контекстов. Если имя отсутствует, то результаты вызова функций С зависят от реализации.
Пример назначения глобального объекта локального контекста в зависимости от окружения, в котором выполняется программа:
std:: locale::global(std::locale(""));
В частности, информация о назначенном контексте передается функциям С, которые будут вызываться в будущем. Последствия будут такими же, как при следующем вызове:
std::setlocale(LC_ALL,"");
Тем не менее глобальное назначение локального контекста не заменяет локальные контексты, уже хранящиеся в объектах. Оно лишь заменяет объект локального контекста, копируемый при создании контекста конструктором по умолчанию. Например, вызов locale::global() не влияет на объекты локальных контекстов, хранящиеся в объектах потоков данных. Если вы хотите, чтобы существующий поток данных использовал конкретный локальный контекст, свяжите его с этим контекстом при помощи функции imbue().
Глобально назначенный контекст используется при создании объектов локального контекста конструктором по умолчанию. В этом случае новый контекст представляет собой копию глобально назначенного контекста на момент конструирования. Следующий фрагмент назначает контекст по умолчанию для стандартных потоков данных: // Глобальная регистрация объекта локального контекста для потоков
std::cin.imbue(std::locale()); std::cout.imbue(std::locale()); std::cerr.imbue(std::locale());
При использовании локальных контекстов в C++ важно помнить, что они почти не связаны с локальными контекстами С. Твердо уверенным можно быть только в одном: единый локальный контекст С изменяется при глобальном назначении именованного объекта локального контекста C++. В общем случае нельзя предполагать, что функции С и C++ работают в одних и тех же локальных контекстах.
На следующем шаге мы рассмотрим фацеты.