C++ Boost

Tuple Library : design decisions rationale

名前空間について

その昔、タプルは独立した名前空間にあるべきか、直接boost名前空間にあるべきかについて、議論がなされた。 一般的な原則として、専門的なライブラリ(graphpythonのような)は独立した入れ子の名前空間に入るべきである一方、ユーティリティ的なライブラリは直接boost名前空間に入るべきであった。 タプルはそのどちらとも決めがたい。tupleテンプレートは明らかに汎用的なユーティリティであるが、ライブラリは他にとても多くの名前を、ただtupleテンプレートのために導入する。 タプルは最初は入れ子の名前空間のもとにあった。 議論の結果、タプルの定義はboostの直下に移された。 さらに継続した議論の結果、入れ子の名前空間が再び導入された。 最終的な(真剣にそう願う)解答は、今や、全ての定義を名前空間::boost::tuplesに置き、最もよく使われる名前を、::boost名前空間にも同様に置こうというものである。 これはusing宣言によって実現された(Dave Abrahamsの提案による):

namespace boost {
  namespace tuples {
      ...      
    // 全てのライブラリ コード
      ...
  }
  using tuples::tuple; 
  using tuples::make_tuple;
  using tuples::tie;
  using tuples::get;
}
この配置によって、コンストラクタによる、またはmake_tupleあるいはtie関数によるタプル生成には、名前空間限定子が不要になる。 さらに、タプルを操作する全ての関数はKoenig-lookupで検出される。 唯一の例外は、常に明示的なテンプレート引数とともに呼び出されるため、Koenig-lookupが適用されないget<N>関数である。 そこで、getはusing宣言によって::boost名前空間に持ち上げられた。 こうして、アプリケーション プログラマのためのインタフェイスだけが、実際に名前空間::boostのもとにあることになった。

その他の名前、ライブラリ作者のためのインタフェイス(consリスト、consリストを操作するメタ関数、...)は入れ子の名前空間::boost::tuplesに残された。 名前ignoreset_openset_closeおよびset_delimiterはアプリケーション プログラマのインタフェイスに含まれるものと考えられるが、boost名前空間には入っていないことに注意されたい。 その理由は、ありがちな命名なので名前が衝突する危険があるためである。それに、たぶん、これらはそう頻繁には使われないだろう。

名前空間に魅せられた者たちへ

入れ子の名前空間名tuplesは多少の議論を惹き起こした。 最も自然な命名である'tuple'を使わなかった理論的根拠は、tupleテンプレートと同一の名前を持つことを避けたからである。 しかし、boost librariesでは、名前空間名は一般に複数形ではない。 最初は、名前空間とクラスに同じ名前を使っても、深刻なトラブルは報告されなかったので、'tuples'を'tuple'に変えようかとも考えた。 しかし結局トラブルが見つかった。 gccとedgコンパイラが、名前空間名とクラス名が同一の場合、using宣言を拒絶したのである:

namespace boost {
  namespace tuple {
    ... tie(...);
    class tuple; 
      ...
  }
  using tuple::tie; // ok
  using tuple::tuple; // error
    ...
}
とはいえ、グローバル名前空間では同様のusing宣言はokらしい:
using boost::tuple::tuple; // ok;

consリストの終端マーク(nil, null_type, ...)

タプルは内部的にはconsリストとして表現されている:

tuple<int, int>
cons<int, cons<int, null_type> >
を継承している。 null_typeはリストの終端を示すマークである。最初の案ではnilであったが、この名前はMacOSで使われており、問題を起こすことが予想されたので、代わりにnull_typeが選ばれた。 他にはnull_tおよびunit(SMLにおける空タプル型)も考慮の対象となった。

null_typeは空タプルの内部表現である: tuple<>null_typeから派生している。

要素のインデックス

要素のインデックスを0から始めるか1からにするかは、徹底的のさらに上をゆく議論がなされ、次の所見が得られた:

get<N>(a)またはa.get<N>()(aはタプルで、Nはインデックスである)のシンタックスでタプル要素にアクセスするのは、前者の種類に属すると考えられる。そこで、最初の要素のインデックスは0とされた。

1-ベースの'name like'インデックスを、_1st, _2nd, _3rd, ...のような定数を使って提供しようという提案もなされた。 定数に適切な型を選べば、こんな代替構文も可能になるだろう:

a.get<0>() == a.get(_1st) == a[_1st] == a(_1st);
だが、0-ベース以外のインデックスを提供するのはやめることにした。次の理由による:

タプルの比較

比較演算子は辞書的順序を実装する。 他の順序付け、主にdominance (a < b iff for each i a(i) < b(i))も考慮された。 我々は、辞書的順序は、最も自然な数学的順序付けではないが、日々のプログラミングで最も頻繁に必要とされると信じている。

ストリーム化

タプルのストリーム マニピュレータに設定された文字は、ios_base::xallocによって確保されたlong型のオブジェクト用の記憶域に格納される。 longとストリームの文字型との間の変換にはstatic_castが使われる。 従って、longと相互に変換できない文字型を持つストリームでは、コンパイルに失敗する。 この問題はいつか再考されよう。可能な解決が二つある:

Back to the user's guide

© Copyright Jaakko Järvi 2001.

Japanese Translation Copyright (C) 2003 Yoshinori Tagawa. オリジナルの、及びこの著作権表示が全ての複製の中に現れる限り、この文書の 複製、利用、変更、販売そして配布を認める。このドキュメントは「あるがまま」 に提供されており、いかなる明示的、暗黙的保証も行わない。また、 いかなる目的に対しても、その利用が適していることを関知しない。