ちょっと変態的な関数ポインタ

in

メンバ関数のポインタをvectorに突っ込んで使おうとして手間取ったのでメモ。ググってみたらstructに関数ポインタ変数を宣言すれば簡単にvectorに格納できるのはすぐにわかったのだけれど使い方で一晩悩みました。まだまだです>自分。とりあえず、グローバルな関数なら、

struct func_ptr
{
  int (*func)(const char *);
};
int boo(const char* value)
{
  cout << value << " Boo!" << endl;
}
int foo(const char* value)
{
  cout << value << " Foo!" << endl;
}
int woo(const char* value)
{
  cout << value << " Woo!" << endl;
}
int main (int argc, char* argv[])
{
  vector<func_ptr> v;
  func_ptr fp;
  fp = boo; v.push_back(fp);
  fp = foo; v.push_back(fp);
  fp = woo; v.push_back(fp);
  vector<func_ptr>::iterator itr = v.begin();
  while(itr != v.end())
  {
    (*itr).func("hello");
    ++itr;
  }
}

ってカンジでOK。これをオブジェクトのメンバ関数にするには、明示的にnamespaceが必要になります。

struct func_ptr
{
  int (boofoowoo::*func)(const char *);
};

さらに関数のポインタを取得する場合も明示的に&を指定する必要があります。

func_ptr fp;
fp.func = &boofoowoo::boo;
v.push_back(fp); 
fp.func = &boofoowoo::foo;
v.push_back(fp);
fp.func = &boofoowoo::woo;
v.push_back(fp);

で、問題なのが呼び出しで一晩悩みましたが最終的にはこう書きました。

boofoowoo bfw;
std::vector<boofoowoo::func_ptr>::iterator itr = bfw.v.begin();
while (itr != bfw.v.end())
  {
    (bfw.*((*itr).func))("hello");
    ++itr;
  }

"(bfw.*((*itr).func))("hello")"を順にみると、(*itr)は、fpのことなので(*itr).funcはboo()/foo()/woo()の関数ポインタ、なので*((*itr).func)は関数の実体を指しますよねぇ?と最初はここまで考えて、

*((*itr).func)("hello");

でいけるかと試しましたがそんな関数ないのでもちろんコンパイルエラー。boo()/foo()/woo()は、boofoowooオブジェクトのメンバ関数なのでオブジェクト名の修飾が必要になります。そこで、

bfw.*((*itr).func)("hello")

今度こそいけるかと思ったのですが、これだと"call to non-function `boofoowoo::func_ptr::func"(gcc-3.3)などと言われてしまいます。*演算子より()演算子の優先順位が高いので先に”*((*itr).func)()"が評価されて、そんな関数ないぜ!ってことになるわけです。つまり、さらにカッコで囲んでやる必要があります。

(bfw.*((*itr).func))("hello");

これで、bfwオブジェクトのfunc()ということになります。また、オブジェクト内の別メソッドから呼び出す場合(やりたかったのは実際はこのパタン)は、

void boofoowoo::call_bfw(void)
{
  std::vector<boofoowoo::func_ptr>::iterator itr = v.begin();
  while (itr != v.end())
    {
      (this->*((*itr).func))("hello");
      ++itr;
    }
}

なんとも変態的ではありますけど、switch文で一つ一つ関数を呼び分けるのに比べたらスッキリしていいものです。人に優しい気はしませんが...

添付サイズ
sample.cpp1.16 KB

この記事のトラックバックURL:

http://hippos-lab.com/blog/trackback/311

返信