[解決済み] STL Character Traitsのポイントは何ですか?
質問
私の持っているSGI STLリファレンスには、Character Traitsについてのページがありますが、これがどのように使用されるのかがわかりません?これらはstring.hの関数を置き換えるのでしょうか?それらは
std::string
には使われていないようです。
length()
メソッドで
std::string
はキャラクター特性を利用しません。
length()
メソッドを使用しています。なぜCharacter Traitsが存在するのか、そして実際に使用されることはあるのでしょうか?
どのように解決するのですか?
Character traits は、ストリームや文字列ライブラリの非常に重要なコンポーネントです。 どの文字が格納されているか のロジックから これらの文字に対してどのような操作を行うべきかというロジックから
そもそも、デフォルトのキャラクタの特性クラスである
char_traits<T>
は、C++ 標準では広範囲に使用されています。 例えば
std::string
. むしろ、クラステンプレート
std::basic_string
のようなもので、このようになります。
template <typename charT, typename traits = char_traits<charT> >
class basic_string;
では
std::string
は次のように定義されます。
typedef basic_string<char> string;
同様に、標準的なストリームは次のように定義されます。
template <typename charT, typename traits = char_traits<charT> >
class basic_istream;
typedef basic_istream<char> istream;
では、なぜこれらのクラスはこのような構造になっているのでしょうか? なぜ奇妙な traits クラスをテンプレートの引数として使用しなければならないのでしょうか?
のような文字列を持ちたい場合があるからです。
std::string
のような文字列でありながら、若干異なるプロパティを持ちたい場合があるからです。 この典型的な例としては、大文字小文字を無視した形で文字列を格納したい場合があります。 例えば、文字列を
CaseInsensitiveString
という文字列を作り、それを
CaseInsensitiveString c1 = "HI!", c2 = "hi!";
if (c1 == c2) { // Always true
cout << "Strings are equal." << endl;
}
つまり、大文字小文字の違いだけが異なる2つの文字列が等しく比較されるような文字列ができるんです。
さて、標準ライブラリの作者がtraitを使わずに文字列を設計したとします。 これは、私の状況では全く役に立たない、非常に強力な文字列クラスが標準ライブラリの中にあることを意味します。 この文字列クラスのコードの多くは再利用できません。なぜなら、比較は常に私が望む方法とは逆に動作してしまうからです。 しかし、traitを使うことで、実際に
std::string
を駆動して大文字小文字を区別しない文字列を取得するコードを再利用することが実際に可能です。
C++のISO標準を引っ張り出してきて、文字列の比較演算子がどのように動作するかの定義を見てみると、それらはすべて
compare
関数で定義されていることがわかります。 この関数は、順番に
traits::compare(this->data(), str.data(), rlen)
ここで
str
は比較対象の文字列で
rlen
は 2 つの文字列の長さのうち小さい方です。 これは実に興味深いことで、つまりは
compare
の定義が直接
compare
関数を直接使用します。 その結果、もし新しい traits クラスを定義し、そのクラスに対して
compare
を定義し、それが大文字小文字を区別せずに文字を比較するようにすれば、 文字列クラスを作ることができます。
std::string
と同じように振る舞いますが、大文字小文字を区別せずに扱います。
以下はその例です。 私たちは
std::char_traits<char>
を継承して、私たちが書かない全ての関数のデフォルトの振る舞いを取得しています。
class CaseInsensitiveTraits: public std::char_traits<char> {
public:
static bool lt (char one, char two) {
return std::tolower(one) < std::tolower(two);
}
static bool eq (char one, char two) {
return std::tolower(one) == std::tolower(two);
}
static int compare (const char* one, const char* two, size_t length) {
for (size_t i = 0; i < length; ++i) {
if (lt(one[i], two[i])) return -1;
if (lt(two[i], one[i])) return +1;
}
return 0;
}
};
(私はまた
eq
と
lt
は、それぞれ文字を等しいかどうか、より小さいかどうかを比較するもので、次に
compare
をこの関数の観点で定義しています)。
この traits クラスができたので、次のように定義できます。
CaseInsensitiveString
として定義できます。
typedef std::basic_string<char, CaseInsensitiveTraits> CaseInsensitiveString;
そして、出来上がりです。 これで大文字小文字を区別しない文字列が完成です!
もちろん、これ以外にもtraitを使用する理由はあります。 例えば、ある固定サイズの文字型を使用する文字列を定義したい場合、特殊化した
char_traits
を特殊化し、その型から文字列を作ることができます。 例えばWindowsのAPIでは、このような型に
TCHAR
という型があり、前処理で設定したマクロによって幅の狭い文字になったり広い文字になったりする。 この型から文字列を作ることができる。
TCHAR
を書くことによって
typedef basic_string<TCHAR> tstring;
そして、今度は文字列の
TCHAR
s.
これらの例のすべてにおいて、ある型の文字列を取得するために、あるテンプレート型のパラメータとしてある形質クラス(または既に存在するものを使用)を定義していることに注意してください。 これの要点は
basic_string
の作者が traits の使用方法を指定するだけで、デフォルトの文字列型にはないニュアンスや癖のある文字列を取得するために、デフォルトではなく私たちの traits を使用するように魔法のようにできることです。
これが役に立つことを願っています!
EDIT : phoojiさんが指摘されているように、このtraitの概念はSTLだけで使われているわけでもなく、C++に特有なものでもないようです。 まったくもって恥知らずな自画自賛ですが、少し前に私は 三項探索木の実装 (基数木の一種 で説明されています。 で説明されています)、trait を使って任意の型の文字列を格納し、クライアントが格納することを望むあらゆる比較型を使用するものです。 これが実際に使用されている例を見たいのであれば、興味深い読み物かもしれません。
EDIT
: というあなたの主張に対して
std::string
は使用しません。
traits::length
を使用しませんが、いくつかの場所では使用することが判明しています。 最も顕著なのは
std::string
から
char*
C スタイルの文字列の場合、文字列の新しい長さは
traits::length
を呼び出すことで得られる。 どうやら
traits::length
は主に C スタイルの文字列を扱うために使用されます。
std::string
は任意の内容の文字列を扱うために使用されます。
関連
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] テスト
-
[解決済み】抽象クラス型の無効なnew-expression
-
[解決済み】浮動小数点例外エラーが発生する: 8
-
[解決済み】「Expected '(' for function-style cast or type construction」エラーの意味とは?
-
[解決済み] 解決済み] `pthread_create' への未定義の参照 [重複] [重複
-
[解決済み] gdbを使用してもデバッグシンボルが見つからない
-
[解決済み】Enterキーを押して続行する
-
[解決済み] 配列のベクトルを扱う正しい方法
-
[解決済み] スタックアロケーションにより初期化されていない値が作成された
-
[解決済み】エラー。引数リストに一致するコンストラクタのインスタンスがない