その昔、タプルは独立した名前空間にあるべきか、直接boost
名前空間にあるべきかについて、議論がなされた。
一般的な原則として、専門的なライブラリ(graphやpythonのような)は独立した入れ子の名前空間に入るべきである一方、ユーティリティ的なライブラリは直接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
に残された。
名前ignore
、set_open
、set_close
およびset_delimiter
はアプリケーション プログラマのインタフェイスに含まれるものと考えられるが、boost
名前空間には入っていないことに注意されたい。
その理由は、ありがちな命名なので名前が衝突する危険があるためである。それに、たぶん、これらはそう頻繁には使われないだろう。
入れ子の名前空間名tuplesは多少の議論を惹き起こした。
最も自然な命名である'tuple'を使わなかった理論的根拠は、tupleテンプレートと同一の名前を持つことを避けたからである。
しかし、boost librariesでは、名前空間名は一般に複数形ではない。
最初は、名前空間とクラスに同じ名前を使っても、深刻なトラブルは報告されなかったので、'tuples'を'tuple'に変えようかとも考えた。
しかし結局トラブルが見つかった。
gccとedgコンパイラが、名前空間名とクラス名が同一の場合、using宣言を拒絶したのである:
とはいえ、グローバル名前空間では同様のusing宣言はokらしい:
namespace boost {
namespace tuple {
... tie(...);
class tuple;
...
}
using tuple::tie; // ok
using tuple::tuple; // error
...
}
using boost::tuple::tuple; // ok;
タプルは内部的には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からにするかは、徹底的のさらに上をゆく議論がなされ、次の所見が得られた:
bind1st
, bind2nd
, pair::first
など。get<N>(a)
またはa.get<N>()
(a
はタプルで、N
はインデックスである)のシンタックスでタプル要素にアクセスするのは、前者の種類に属すると考えられる。そこで、最初の要素のインデックスは0とされた。
1-ベースの'name like'インデックスを、_1st
, _2nd
, _3rd
, ...のような定数を使って提供しようという提案もなされた。
定数に適切な型を選べば、こんな代替構文も可能になるだろう:
だが、0-ベース以外のインデックスを提供するのはやめることにした。次の理由による:
a.get<0>() == a.get(_1st) == a[_1st] == a(_1st);
_1st
, ...のような)を定義する余地は少ない。
それらは、bindingやlambdaライブラリに譲り、より良い用途に使ってもらおう。a[_1st]
(またはa(_1st)
)構文は魅力的で、もう少しで我々にインデックス用の定数を追加させるところだった。しかし、0-ペースの添字はC++に深く深く根ざしている。我々は混乱を恐れた。
タプルのストリーム マニピュレータに設定された文字は、ios_base::xalloc
によって確保されたlong
型のオブジェクト用の記憶域に格納される。
long
とストリームの文字型との間の変換にはstatic_cast
が使われる。
従って、longと相互に変換できない文字型を持つストリームでは、コンパイルに失敗する。
この問題はいつか再考されよう。可能な解決が二つある:
char
型のみをタプルの区切り文字として認め、ストリームの文字型との間の変換にwiden
とnarrow
を使う。
これは常にコンパイルされるだろうが、一部のマニピュレータ呼び出しで、(数個のデフォルトの文字が)期待したのと違う字になるかもしれない。ios_base::xalloc
で確保した空間に入れるということである。
誰かやってくんない?© Copyright Jaakko Järvi 2001.
Japanese Translation Copyright (C) 2003 Yoshinori Tagawa. オリジナルの、及びこの著作権表示が全ての複製の中に現れる限り、この文書の 複製、利用、変更、販売そして配布を認める。このドキュメントは「あるがまま」 に提供されており、いかなる明示的、暗黙的保証も行わない。また、 いかなる目的に対しても、その利用が適していることを関知しない。