しのはらのC++実験室トップページ
「移植性の高いプログラムの書き方」トップページ
M__NO_NAMESPACE
が定義されているとします。どうもここまでは誰もが思い付くことらしいのです。 サークルの先輩にもほとんど同じ事をしている人を発見して、 少しうれしかったです。#ifndef M__NO_NAMESPACE # define M__BEGIN_NAMESPACE namespace mylib{ # define M__END_NAMESPACE } # define M__USING_NAMESPACE using namespace mylib; # define M__NAME_SPEC ::mylib #else # define M__BEGIN_NAMESPACE # define M__END_NAMESPACE # define M__USING_NAMESPACE # define M__NAME_SPEC #endif
M__NAME_SPEC
マクロだけは苦心したんです。
その辺を説明しようと思います。
M__BEGIN_NAMESPACE
マクロと
M__END_NAMESPACE
マクロによって、
ライブラリのHやCPPファイルのクラス宣言や定義を囲みます。
そうすることでnamespaceが有効なコンパイラでは、
それらを適切な名前空間に配置できます。M__USING_NAMESPACE
マクロを使用します。これはnamespaceに対するusing宣言に置換されます。M__NAME_SPEC
(上の定義を参照)
について説明します。X
というクラスがあるとすれば、
M__NAME_SPEC::X
という表記は、
その時のスコープに関係なく同一のクラスX
を表わすことになります。
つまり絶対表現です。この様子を示します。
表記 | namespace無し | namespace有り |
M__NAME_SPEC |
/*無し*/ |
::mylib |
M__NAME_SPEC::X |
::X |
::mylib::X |
mylib
)
にあるクラスの中からクラスの外の識別子を、
曖昧さ無く参照するために使おうとしたものです。メンバ関数M__BEGIN_NAMESPACE class Matrix{ /* ... */ public: friend void inverse(Matrix& ans, const Matrix& m); void inverse(){ M__NAME_SPEC::inverse(*this,Matrix(*this)); // この上の行に注目 } }; M__END_NAMESPACE
inverse
からfriend関数inverse
を呼び出したいのですが、
同名のメンバ関数がfriend関数を隠してしまうために、
スコープ解決演算子が必要になるわけです。
クラス自体がグローバルである場合は::inverse
とすれば良いのですが、
クラス自体がnamespaceに囲まれている場合はmylib::inverse
あるいは::mylib::inverse
と書かねばなりません。
その区別のために作ったのがM__NAME_SPEC
マクロなわけです。
M__NAME_SPEC
マクロには直後の::
(ダブルコロン)を含めていました。
マクロを使用する場所では当然::
を書きません。
つまり、
M__NAME_SPEC inverse(/*..... */ );
のように書いていたのです。これでBorland C++やWatcom C/C++では、
全く問題がなかったのです。::
の後の空白」を許さないらしいのでした。
(ちなみに現在の最新バージョンではその問題はなくなっているようです。)そうして結局は最もスマートな、このページの最初に示したやり方に、 落ち着いたわけです。#ifndef M__NO_NAMESPACE # define M__NAME_SPEC(x) ::bslib::x #else # define M__NAME_SPEC(x) ::x #endif