25 Localization library [localization]

25.4 Standard locale categories [locale.categories]

25.4.8 Program-defined facets [facets.examples]

Программа на C ++ может определять фасеты, которые должны быть добавлены к языку и использоваться так же, как встроенные фасеты. Для того, чтобы создать новый интерфейс фасетки, программа C ++ просто вывести из locale​::​facet класса , содержащего статический член: static locale​::​id id.

[ Note: Шаблоны функций-членов языкового стандарта проверяют его тип и класс хранения. ]end note

[ Example: Традиционная глобальная локализация по-прежнему проста:

#include <iostream>
#include <locale>
int main(int argc, char** argv) {
  using namespace std;
  locale::global(locale(""));           // set the global locale
                                        // imbue it on all the std streams
  cin.imbue(locale());
  cout.imbue(locale());
  cerr.imbue(locale());
  wcin.imbue(locale());
  wcout.imbue(locale());
  wcerr.imbue(locale());

  return MyObject(argc, argv).doit();
}

end example]

[ Example: Возможна большая гибкость:

#include <iostream>
#include <locale>
int main() {
  using namespace std;
  cin.imbue(locale(""));        // the user's preferred locale
  cout.imbue(locale::classic());
  double f;
  while (cin >> f) cout << f << endl;
  return (cin.fail() != 0);
}

В европейской локали с вводом 3.456,78вывод 3456.78. ]end example

Это может быть важно даже для простых программ, которым может потребоваться запись файла данных в фиксированном формате, независимо от предпочтений пользователя.

[ Example: Вот пример использования локалей в интерфейсе библиотеки.

// file: Date.h
#include <iosfwd>
#include <string>
#include <locale>

class Date {
public:
  Date(unsigned day, unsigned month, unsigned year);
  std::string asString(const std::locale& = std::locale());
};

std::istream& operator>>(std::istream& s, Date& d);
std::ostream& operator<<(std::ostream& s, Date d);

Этот пример иллюстрирует два архитектурных использования класса locale.

Первый является аргументом по умолчанию в Date​::​asString(), где по умолчанию используется глобальный (предположительно предпочтительный для пользователя) языковой стандарт.

Второй - в операторах << и >>, где локаль «путешествует автостопом» на другом объекте, в данном случае на потоке, до точки, где это необходимо.

// file: Date.C
#include "Date"                 // includes <ctime>
#include <sstream>
std::string Date::asString(const std::locale& l) {
  using namespace std;
  ostringstream s; s.imbue(l);
  s << *this; return s.str();
}

std::istream& operator>>(std::istream& s, Date& d) {
  using namespace std;
  istream::sentry cerberos(s);
  if (cerberos) {
    ios_base::iostate err = goodbit;
    struct tm t;
    use_facet<time_get<char>>(s.getloc()).get_date(s, 0, s, err, &t);
    if (!err) d = Date(t.tm_day, t.tm_mon + 1, t.tm_year + 1900);
    s.setstate(err);
  }
  return s;
}

end example]

Объект языкового стандарта может быть расширен новым аспектом, просто создав его с экземпляром класса, производного от locale​::​facet. Единственный членid, который должна определять программа C ++, - это статический член , который идентифицирует интерфейс вашего класса как новый аспект.

[ Example: Классификация японских иероглифов:

// file: <jctype>
#include <locale>
namespace My {
  using namespace std;
  class JCtype : public locale::facet {
  public:
    static locale::id id;       // required for use as a new locale facet
    bool is_kanji (wchar_t c) const;
    JCtype() { }
  protected:
    ~JCtype() { }
  };
}

// file: filt.C
#include <iostream>
#include <locale>
#include "jctype"               // above
std::locale::id My::JCtype::id; // the static JCtype member declared above.

int main() {
  using namespace std;
  using wctype = ctype<wchar_t>;
  locale loc(locale(""),        // the user's preferred locale ...
         new My::JCtype);       // and a new feature ...
  wchar_t c = use_facet<wctype>(loc).widen('!');
  if (!use_facet<My::JCtype>(loc).is_kanji(c))
    cout << "no it isn't!" << endl;
}

Новый фасет используется точно так же, как и встроенные фасеты. ]end example

[ Example: Заменить существующий фасет еще проще. Код не определяет член, id потому что он повторно использует numpunct<charT> интерфейс фасета:

// file: my_­bool.C
#include <iostream>
#include <locale>
#include <string>
namespace My {
  using namespace std;
  using cnumpunct = numpunct_byname<char>;
  class BoolNames : public cnumpunct {
  protected:
    string do_truename()  const { return "Oui Oui!"; }
    string do_falsename() const { return "Mais Non!"; }
    ~BoolNames() { }
  public:
    BoolNames(const char* name) : cnumpunct(name) { }
  };
}

int main(int argc, char** argv) {
  using namespace std;
  // make the user's preferred locale, except for...
  locale loc(locale(""), new My::BoolNames(""));
  cout.imbue(loc);
  cout << boolalpha << "Any arguments today? " << (argc > 1) << endl;
}

end example]