環境:VS2005
以下のようなクラステンプレートで
staticなメンバである配列ms_Array[]を
例えば,「{0,1,2, ..., N-1}で初期化したい」のですが…
「該配列に初期値を入れたよフラグ(staticなbool型メンバ変数)を作って
コンストラクタ内で,最初のインスタンスが値を入れる」
という書き方しか思いつきません.
より良い(? 一般的な?)方法は無いものでしょうか.
template< size_t N >
class CTest
{
private:
static int ms_Array[ N ]; //←この配列を初期化したい
};
template< size_t N >
int CTest< N >::ms_Array[ N ]; //実体定義
> コンストラクタ内で,最初のインスタンスが値を入れる」
スタティックメンバーである以上、オブジェクトを生成せずに使用できるわけ
で、そうなればコンストラクタの走る余地はありません。
なので、以下のような感じで正解なのでは?
template< size_t N >
int CTest< N >::ms_Array[ N ] = {1, 2, 3 ,5}; //実体定義
書いていて気づいた。
これだと、N が無意味ですね。
その初期値ってのがどういう性質かで話は違う・・・
CTest<2>::ms_Array と CTest<3>::ms_Array で初期値が違うのであれば
それは「初期値が違う」が故に template で記述するべきでない、のだろう。
逆に、すべての CTest<N> で初期値が同じ、であるなら、実用的には
その初期値はすべて0くらいしかありえないわけだけど。
あまりかっこよくない一例を挙げてみるテスト。
> 該配列に初期値を入れたよフラグ(staticなbool型メンバ変数)を作って
ここまでは同じ
> コンストラクタ内で,最初のインスタンスが値を入れる
これを避けるための「古典的」な方策であれば、たとえば
template<int N> struct test_t {
static int (&static_arrayfunc())[N] {
static int initdone;
static int static_array[N];
if (initdone==0) { /*初期化*/ initdone=1; }
return static_array;
}
};
などのように static メンバー関数のローカル変数として閉じ込めてしまうとか。
# マルチスレッドのための排他処理をしていないので実用に供する場合は注意。
> # マルチスレッドのための排他処理をしていないので実用に供する場合は注意。
C++11(VS2012)なら call_once がつかえますねー
template<int N> struct test_t {
static once_flag flag;
test_t() { call_once(flag, [&](){ 初期化 });
};
しばらくネットの使えない状況下にあったため
放置状態になってしまいました.申しわけありませんでした.
問題の配列メンバはインスタンスが生成される前に参照されることはないので
とりあえずコンストラクタ内で一度だけ初期値を入れる形のままとしましたが,
初期化済を示すためのフラグをstaticメンバ関数無いに移す等くらいはできそうですね.
皆様,ありがとうございました.