## 5.5 電話番号のファセットクラス

ここでは、電話番号のファセットクラスの実装を試みます。このファセットに必要な情報を以下に示します。

- ファセットには所在地の情報が必要です。電話番号は国内と国際用では書式が異なるためです。たとえば、ドイツの番号の書式は、国内用では (089) / 636-48018 となりますが、国際用では、 +1-49-89-636-48018 となります。

- ファセットでは、国際電話をかける際の接頭辞が必要です。たとえば、アメリカ合衆国から海外に電話をするときは 011、ドイツからは 00、フランスからでは 19 になります。

- ファセットでは、個々の国別コードを調べるかわりにニモニックを使用できるように、すべての国別コードのテーブルにアクセスできるものとします。たとえば、日本の国別コードを知らない場合でも、これは日本のどこかの電話番号である」と判断するために必要な情報です。

### 5.5.1 データメンバーの追加

以下の電話番号の書式設定ファセットクラスのクラス宣言は、ファセットオブジェクト自体の所在地情報のデータメンバーと、国際電話用の接頭辞が追加されています (以下のコードの //2 と //3 を参照)。国別コードテーブルの追加は、今回は省略しています。

>     class phone_put: public locale::facet {
>     public:
>       typedef string string_t;
>       static locale::id id;
>       phone_put(size_t refs = 0) : locale::facet(refs)
>                                  , myCountryCode_("")
>                                  , intlPrefix_("")      {  }
>      string_t put(const string_t& ext,
>                   const string_t& area,
>                   const string_t& cnt) const;
>     protected:
>       phone_put( const string_t& myC                              //1
>                , const string_t& intlP
>                , size_t refs = 0)
>                : locale::facet(refs)
>                , myCountryCode_(myC)
>                , intlPrefix_(intlP)   {  }
>       const string_t myCountryCode_;                              //2
>       const string_t intlPrefix_;                                 //3
>     };

このクラスが、実際にロケール依存の電話番号の書式設定を実装するファセットクラスの基底クラスとして機能する点に注意してください。これによって、公開コンストラクタを拡張しなくても、保護コンストラクタをかわりに追加して対応しています (先の //1 参照)。

### 5.5.2 国別コードの追加

ここでは、先のクラス宣言で省略した国際国別コードを追加する際の問題について考えます。図 14 に示すように、国別コードは、国別コードを国名のニモニックに関連付ける文字列のマップとして設定します。

#### 図 14 -- 国別コードを国名のニモニックに関連付けるマップ

次のコードでは、国別コードテーブルを追加します。

>     class phone_put: public locale::facet
>     {
>      public:
>        class prefixMap_t : public map<string,string>             //1
>        {
>         public:
>            prefixMap_t() { insert(tab_t(string("US"),string("1")));
>            insert(tab_t(string("De"),string("49")));
>            // ...
>        }
>     };
>        static const prefixMap_t* std_codes()                     //2
>               { return &stdCodes_; }
>      protected:
>        static const prefixMap_t stdCodes_;                       //3
>     };

国別コードのテーブルは、すべての電話番号ファセットオブジェクトに対して有効な定数テーブルなので、静的データメンバー stdCodes_ として追加します (`//3` 参照)。このデータメンバーの初期化は、クラス prefixMap_t にカプセル化されます (`//1` 参照)。テーブルにアクセスできるように、利便性を考えて、関数 std_codes() を追加します (`//2` 参照)。

構成は簡単ですが、静的国別コードテーブルが 1 つしかないため、柔軟性が低すぎます。ニモニックは、異種言語間ではロケールによって異なる点を考慮する必要があります。ニモニックはおそらく不必要であり、実際に必要なのは、実際の国別コードに対応してさらに名前の部分を拡張することです。

柔軟性を高めるために、任意のテーブルで作業できる機能を追加します。個々の国別コードテーブルまでのポインタは、ファセットオブジェクトの構築時に設定することができます。図 15 の静的テーブルはデフォルトになります。

#### 図 15 -- 国別コードを国名に関連付けるマップ

テーブルをポインタとして使用するため、テーブルの宛先になるメモリー管理に注意する必要があります。ファセットを削除するときに、用意したテーブルも削除する必要があるかどうかは、フラグを使用して判断します。次のコードは、テーブルとそれに対応するフラグの使用例を示したものです。

>     class phone_put: public locale::facet {
>     public:
>       typedef string string_t;
>       class prefixMap_t;
>       static locale::id id;

>       phone_put( const prefixMap_t* tab=0                         //1
>                , bool del = false
>                , size_t refs = 0)
>                : locale::facet(refs)
>                , countryCodes_(tab), delete_it_(del)
>                , myCountryCode_(""), intlPrefix_("")
>       { if (tab)   {  countryCodes_ = tab;
>                       delete_it_ = del;   }
>         else       {  countryCodes_ = &stdCodes_;                 //2
>                       delete_it_ = false; }
>       }
>       string_t put(const string_t& ext,
>                    const string_t& area,
>                    const string_t& cnt) const;

>       const prefixMap_t* country_codes() const                    //3
>       { return countryCodes_; }

>       static const prefixMap_t* std_codes()    { return &stdCodes_; }
>     protected:
>       phone_put(const string_t& myC, const string_t& intlP
>               , const prefixMap_t* tab=0, bool del = false
>               , size_t refs = 0)
>               : locale::facet(refs)
>               , countryCodes_(tab), delete_it_(del)
>               , myCountryCode_(myC), intlPrefix_(intlP)
>       { ... }
>       virtual ~phone_put()
>       { if(delete_it_)
>           countryCodes_->prefixMap_t::~prefixMap_t();             //4
>       }

>       const prefixMap_t* countryCodes_;                           //5
>       bool delete_it_;
>       static const prefixMap_t stdCodes_;
>       const string_t myCountryCode_;
>       const string_t intlPrefix_;
>     };

//1 | コンストラクタは、国別コードテーブルまでのポインタを使用するように改善し、共に設定したテーブルのメモリー管理用のフラグも追加します。
//2 | テーブルがない場合は、静的テーブルをデフォルトでインストールします。
//3 | 利便性を考えて、現在のテーブルまでのポインタを返す関数を追加します。
//4 | メモリー管理フラグのステータスに応じてテーブルを削除します。
//5 | 現在の国別コードテーブルまでのポインタを保持する保護データメンバーを追加し、また対応するメモリー管理フラグも追加します。

Copyright (c) 1998, Rogue Wave Software, Inc.
このマニュアルに関する誤りのご指摘やご質問は、電子メールにてお送りください。

OEM リリース, 1998 年 6 月