LoginSignup
3
2

More than 5 years have passed since last update.

インスタンスのメンバ関数のアドレスを取得するときは受け側の型に注意する(C++, gcc)

Last updated at Posted at 2016-03-30

エラー詳細

コンパイラにgccを使ってC++のコードを書いていた時にこんなエラーが出ました.
ISO C++ forbids taking the address of a bound member function to form a pointer to member function.

記事の結論から言うと,

  • インスタンスを生成して呼ばれたメンバ関数のアドレスは、受け側の関数ボインタの型を意識して受け渡す.
  • staticなメンバ関数のアドレスなら取得可能.

だそうです.C++の仕様で禁止されているらしい.

関数ポインタに代入するところでエラーが発生

GSL科学技術計算ライブラリを使っている中でこのエラーと遭遇.

公式のリファレンスには
int(* f)(const gsl_vector* x, void* params, gsl_vector* f)
という関数ポインタに値を代入するように書いてあった.

なので別クラスで作ったint型の関数のアドレスを代入しようと考え,

/* このクラスのメンバ関数のアドレスを取得したい */
Class FooClass{
 public:
  int varFunc();
};

/* 実際に呼び出したmain処理が以下(イメージ) */
FooClass* foo = new FooClass();
f = &(foo->varFunc);

のような書き方をしてたんですね.
そしたら見事に,

 エラー: ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say ‘&FooClass::varFunc’ [-fpermissive]
  f.f  = &(foo->varFunc);

と言われてしまいました.

そこで原因を調べたところ静的メンバのアドレスであれば取得できる模様.
助言に従い以下のように修正しました.

/* このクラスのメンバ関数のアドレスを取得したい */
Class FooClass{
 public:
  static int varFunc();
};

/* 実際に呼び出したmain処理が以下(イメージ) */
f = &(FooClass::varFunc);

するとコンパイルはすんなり通りました。

修正自体はすごい簡単だったんですけど、もともと動的メンバとして作成した関数の修正は時間がかかりました.

追記

(2016/03/31)
メンバ関数を無理にstaticに変更してコード全体に影響してしまう場合は、ラッパーを用意するなどして対応するのもあり!

おまけ(GSLはもともとCのライブラリなので上記のエラーには注意する!)

GSLのWikiにも

GSL は C 言語ライブラリであるため、C++のクラスから利用できる。しかしメンバー関数へのポインタは、その型が関数へのポインタとは異なる[2]ため、利用できない。関数へのポインタは、静的に定義された関数 (C言語における一般的な関数定義によるもの) に対して利用する必要がある。

と書いてありました(汗)

参考

http://vipprog.net/wiki/prog_lang/c.html

3
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2