読者です 読者をやめる 読者になる 読者になる

C++のstaticに関するまとめ

C++

static(メンバ)変数への代入について知識がうろ覚えだったので、整理した。要点は以下。

  1. staticな変数は宣言と同時に代入する
  2. staticなstruct型の初期化は{}で行う.
  3. class内のstaticなメンバに代入するときはクラスの宣言の外で代入.また型の指定が必要.
  4. class内struct型がprivateに宣言されていてもクラスの外で初期化できる
  5. class templateのstaticなメンバ変数、関数への代入はtemplateを指定する
  6. staticな関数ポインタはtemplate関数で初期化できる

前提知識1

前提知識として関数ポインタの宣言は以下のようにする。

引数名は省略可能。

戻り値 (*変数名)(引数型1 引数名1, 引数型2 引数名2, 続く)
void (*hensu_mei)(void* hoge, double* hage);

前提知識2

c++struct型とclassは(メンバの宣言がデフォルトでpublicかどうかの違いはあるが)基本的に区別がない。

1. staticな変数は宣言と同時に代入する

よくみる構文なので当たり前だが、後述のstaticメンバの初期化とはちょっと異なるのに注意がいる。

/******************************************************************************
 * staticな変数は宣言と同時に代入.
 ******************************************************************************/
void static_test_f0(void*) {
}
static void (*static_test_fp)(void *) = static_test_f0; //OK

//static void (*static_test_fp)(void* hoge);
//static_test_fp = static_test_f0; //NG

2. staticなstruct型の初期化は{}で行う.

staticなstruct型の場合。{}記号の一つの用法。

/******************************************************************************
 * staticなstruct型の初期化は{}で行う.
 ******************************************************************************/

void static_class_test_f(void *) {
}

struct static_class_test {
    void (*test)(void *);
    double hoge;
};

static struct static_class_test static_class_test_instance =  {
    static_class_test_f,
    1.0
};

3. class内のstaticなメンバに代入するときはクラスの宣言の外で代入. また型の指定が必要.

staticな変数のとの大きな違いは下記。 * staticの宣言と代入を別の場所で行う * 型の指定が必要になる

/******************************************************************************
 * class内のstaticなメンバに代入するときはクラスの宣言の外で代入.
 * また型の指定が必要.
 ******************************************************************************/
void static_test_f1(void*) {
}
class static_test1 {
public:
    static_test1() {};

    static void (*test)(void *);
    //static void (*test)(void *) = static_test_f1; //NG
    //void (*test)(void *) = static_test_f1; //NG
    static double hoge;
    //static double hoge = 1.0; //NG
};

void (*static_test1::test)(void *) = static_test_f1;
//static_test1::test = static_test_f1; //NG
double static_test1::hoge = 1.0;
//static_test1::hoge = 1.0; //NG

4. class内struct型がprivateに宣言されていてもクラスの外で初期化できる

staticなstruct型のメンバも上記2と3の組み合わせで代入できる。

注意すべき点はstaticなstruct型がprivateなクラス内struct型であっても問題ないという所。

/******************************************************************************
 * class内struct型がprivateに宣言されていてもクラスの外で初期化できる
 ******************************************************************************/
class initialize_struct_test1 {
private:
    struct vtable {
        void (*draw)(void*);
        double hoge;
    };

public:
    initialize_struct_test1();
    static vtable _vTable;
};

void test1(void *hoge) {
    //initialize_struct_test1::vtable hage; //NG
}

initialize_struct_test1::vtable initialize_struct_test1::_vTable = {
    test1,
    2.0
};
//instaneがないので.は使えない
//void (*initialize_struct_test1::_vTable.test)(void*) = test2; //NG
//double initialize_struct_test1::_vTable.hoge = 2.0; //NG

5. class templateのstaticの時はtemplateも指定する

class templateにstaticなメンバがあるときはtemplateを指定して代入する。

/******************************************************************************
 * class templateのstaticの時はtemplateも指定する
 ******************************************************************************/
template <typename T>
class class_teplate_test {
public:
   class_teplate_test();

   static void (*test)(void*); 
   static double hoge;
};

void test2(void *hoge) {
}

template <typename T>
void (*class_teplate_test<T>::test)(void *) = test2;
template <typename T>
double class_teplate_test<T>::hoge = 10.0;

6. staticな関数ポインタはtemplate関数で初期化できる

staticな関数ポインタに限った話ではないが、template関数の用法。

/******************************************************************************
 * staticなtemplate関数はtemplateの指定が必要.
 ******************************************************************************/
template <typename T>
void template_func_test_f1(T*) {
}

void template_func_test_f2(int*) {
}

static void (*template_func_test)(char*) = template_func_test_f1;

//こういうのがやりたいならメタプログラミング
//template <typename T>
//static void (*template_func_test)(T*) = template_func_test_f2;

参考

C++の記号一覧 (List of C++ symbols) - gununuの日記