通常ソース(CPP)ファイルでstaticメンバー変数やconstメンバー変数の初期化を行うが、ヘッダーファイル内で初期化したい時がある。そんな時どうするかのTips。
失敗例
C++で次のように初期化できれば一番いいのだがそれはできない。(private,public記述が面倒なのでclassではなくstructで)
1 2 3 4 5 |
struct Test { static string static_member = "hoge"; const string const_member = "hoge"; }; |
これをコンパイルすると両者に対し次のようなエラーが現れる。
エラー 1 error C2864: ‘Test::static_member’ : スタティック const 整数データ メンバ以外をクラス内で初期化することはできません
また、constの場合には
1 2 3 4 5 6 |
struct Test { const string const_member; }; string Test::const_member( "hoge" ); |
こんな書き方をしてもコンパイラに怒られる。
error C2761: ‘const std::string Test::const_member’ : メンバ関数の再宣言はできません。
またどこかでstatic変数をこのように初期化するとリンカでリンクエラーが発生する。(ヘッダーを多重にincludeしてる時)
1 2 3 4 5 6 |
struct Test { static string static_member; }; string Test::static_member( "hoge" ); |
エラー 1 error LNK2005: “public: static class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > Test::static_member” (?static_member@Test@@2V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A) は既に Test.obj で定義されています。 hoge.obj
こんな風に怒られてしまう。
成功例
constメンバー変数に対しては当然コンストラクタで初期化をするという形で解決できる。staticメンバー変数に対しては、__declspec( selectany )で解決することができる。
__declspecはMicrosoft特有の仕様(Microsoft Specific)とMSDNで書かれている通りVC++特有のコマンドである。
これらをふまえて例えばこんな感じ。
1 2 3 4 5 6 7 8 9 |
struct Test { static string static_member; const string const_member; Test() : const_member( "hoge" ) {}; }; __declspec( selectany ) string Test::static_member( "hoge" ); |
こうすることで両者を解決することができる。
static const int
スタティックなconst整数については、どうやら宣言部分で初期化できるようだ。
1 2 3 4 |
struct Test { static const int n = 0; }; |
そういえば関係ないが、declspecのdeclというのはなんだろうか、、、Yahooの辞書だとdec・la・ma・tion、declamationというのが引っかかる。この意味が「劇的効果をねらう演説」とのこと。劇的効果をねらう仕様という宣言なんだろうか、、、と思ったがよく考えればdeclare specificationみたいことなのかな、、、