プログラミング/C++/C++テクニック の変更点
更新- 追加された行はこの色です。
- 削除された行はこの色です。
- プログラミング/C++/C++テクニック へ行く。
- プログラミング/C++/C++テクニック の差分を削除
[[公開メモ]] #contents * 概要 [#va06a887] C++ は長らく触っていなかったので、 えっ、と思うようなことを知らずに苦労しています。 覚えた内容をここにメモ。 * テンプレート引数クラスへの friend 指定 [#b7e0f054] cygwin 上の g++ (GCC) 4.3.4 で、 LANG:cpp(linenumber) template<class T> class Test { friend class T; }; としたところ friend の行で LANG:console $ g++ test.cpp test.cpp:4: error: using template type parameter 'T' after 'class' test.cpp:4: error: friend declaration does not name a class or function というエラーが出てしまいました。 テンプレート引数となった型 T に対して、 正攻法では friend 関係を構築できないようなのです。 これは C++ の仕様らしいのですが、これを回避するための方法として、 以下を見つけました。 LANG:cpp(linenumber) template<class T> class Test { struct alias_maker { typedef T T_alias; }; friend class alias_maker::T_alias; }; 凄く小手先なんですが・・・いいんですかね、これで。 この件について http://www.byte.com/documents/s=9162/cujexp0312wilson2/ に詳しい解説があったようです。 今は見られなくなっていたので webarchive 経由で見たところ、http://replay.waybackmachine.org/20041212160407/http://www.byte.com/documents/s=9162/cujexp0312wilson2/ この回避方法および、その他の回避方法に関する互換性情報がまとめられていました。 ||||BGCOLOR(YELLOW):||c |Compiler |Form #1 |Form #2 |Form #3 |Form #4| |Borland C++ (5.51 & 5.6) |Yes | | | | |CodeWarrior (7 and 8) | |Yes |Yes |Yes| |Comeau (4.3.0.1) |non-strict only |non-strict only |non-strict only |non-strict only| |Digital Mars (8.26-8.37) |Yes |Yes |Yes |Yes| |GCC 2.95 |Yes | | | | |GCC 3.2 | |Yes |Yes | | |Intel (6 and 7) |Yes |Yes |Yes |Yes| |Visual C++ (4.2 - 7.1) |Yes | |Yes |Yes, except 4.2| |Watcom (11 and 12) |Yes |Yes |Yes || だそうです。 上記の解決法はこのうち Form #3 にあたり、~ 何にも考えずに friend T と書くのが Form #1、~ 何にも考えずに friend class T と書くのが Form #2、~ friend_maker をテンプレートクラスにしてもう一段ややこしくしたのが Form #4~ です。 リンク先では #ifdef を使って Form #1 と Form #3 とを選んで使うコード例も挙げられていました。 * ローカルな static 変数の初期値 [#s970d922] cygwin 上の g++ (GCC) 4.3.4 で、 LANG:cpp(linenumber) int test() { static int i = 0; return i; } #include <iostream> int main(int argc, const char* argv[]) { std::cout << test() << std::endl; } の結果が、 LANG:console $ g++ test.cpp $ ./a.exe 67600 となって困っています。 納得できないことに、3 行目を i = 0 ではなく i = 1 にして、 LANG:cpp(linenumber) int test() { static int i = 1; return i; } では正しく 1 が表示されます。 LANG:console $ g++ test.cpp $ ./a.exe 1 初期値が 0 の時のみ、ローカル static 変数の初期化がうまく行っていないのです。 ちなみに、i に初期値を与えず static int i; としても、 結果は 0 を与えたときと同じでした。 そういう仕様でしたっけ??? もしかしたら cygwin のローダーがおかしい??? * static コンストラクタのようなもの [#sd28d8f7] C# には static コンストラクタというのがあって、 static メンバーの初期化等に便利に使えます。 C++ には static コンストラクタはないので、 代替法を探したところ、 http://cppdiary.blog76.fc2.com/blog-entry-11.html を見つけました。 グローバル変数の初期化タイミングで static 関数を呼び出そうという企みのようです。 似たようなことを次のようにしてやってみました。 initial_callback.h LANG:cpp(linenumber) #ifndef INITIAL_CALLBACK_H #define INITIAL_CALLBACK_H template<class T, void func()> class InitialCallback { public: InitialCallback() { func(); } }; #define INITIAL_CALLBACK(t, f) \ InitialCallback<t, t::f> t##_InitialCallback_##f; #endif を作って、次のように使います。 initial_callback_test.cpp LANG:cpp(linenumber) #include "initial_callback.h" #include <iostream> class Square { // InitialCallback を使って table を初期化する static int table[256]; static void StaticInitialize() { for(int i = 0; i < sizeof(table); i++) table[i] = i*i; } public: static int square(int i) { return table[i]; } }; int Square::table[256]; // この宣言で Square::StaticInitialize が初期化時に呼び出されます INITIAL_CALLBACK(Square, StaticInitialize); int main(int argc, const char* argv[]) { std::cout << Square::square(1) << std::endl; std::cout << Square::square(2) << std::endl; std::cout << Square::square(3) << std::endl; std::cout << Square::square(4) << std::endl; } ミソは 21 行目の INITIAL_CALLBACK という宣言です。 ここにクラス名と static 関数名を与えておくと、 グローバル変数の初期化タイミングで、与えた関数が呼び出されます。 実行してみると、ちゃんと Square::table は初期化されて、 LANG:console $ g++ static_initializer_test.cpp $ ./a.exe 1 4 9 16 となりました。 ** スコープによってはうまく行かない [#j738e917] あう、入れ子クラスにこれを使おうとするとうまく行きませんね・・・ LANGUAGE:C++ INITIAL_CALLBACK(SuperClass::Square, StaticInitialize); // InitialCallback<SuperClass::Square, SuperClass::Square::StaticInitialize> // SuperClass::Square_InitialCallback_StaticInitialize; // に展開されて、 // SuperClass::Square_InitialCallback_StaticInitialize // が見つからないといってエラーになります。 その場合にはマクロを使わず、次のように書けばいいですね。 LANGUAGE:C++ InitialCallback<SuperClass::Square, SuperClass::Square::StaticInitialize> SomeUniqueName; SomeUniqueName のところは他とかぶらなければどんな名前でも大丈夫です。 * コメント [#m531470d] #article_kcaptcha **BKUUktaacwaLBa [#d68dc5d5] >[ckvyok] (2013-01-05 (土) 22:41:43)~ ~ WJlBeD , [url=http://clhueczncocw.com/]clhueczncocw[/url], [link=http://fogcjogmaake.com/]fogcjogmaake[/link], http://aumwklrtqztr.com/~ // #comment_kcaptcha
Counter: 23389 (from 2010/06/03),
today: 1,
yesterday: 4