ビルド時に~ is not a class, struct or unionと言われたら


経緯

realsenseからのdepthデータとrgbデータを同期させたくて、ROSのmessage_filtersを使っていたのですが、catkin buildしたときにエラーが発生し、結構ハマったので共有しておきます。

エラー時の状態

最初下のようなスクリプトを書いていました。rgbとdepthのトピックのmsgのタイムスタンプが同じ場合、sammpleFunctionクラスのメンバ関数であるcameraCallback関数を呼び出すという感じです。

sample.cpp
void sampleFunction::init()
{
    ~その他の処理~
    // message_filtersの処理
    message_filters::Subscriber<sensor_msgs::Image> rgb_sub(nodeHandle_, cameraTopicName, cameraQueueSize);
    message_filters::Subscriber<sensor_msgs::Image> depth_sub(nodeHandle_, depthTopicName, depthQueueSize);
    typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::Image, sensor_msgs::Image> MySyncPolicy;
    message_filters::Synchronizer<MySyncPolicy> sync(MySyncPolicy(10), rgb_sub, depth_sub);
    sync.registerCallback(&sampleFunction::cameraCallback);
}

これでcaktin buildすると次のようなエラーメッセージが発生しました。

/usr/include/boost/bind/bind.hpp:75:37: error: ‘void (sample::sampleFunction::*)(const boost::shared_ptr<const sensor_msgs::Image_<std::allocator<void> > >&, const boost::shared_ptr<const sensor_msgs::Image_<std::allocator<void> > >&)’ is not a class, struct, or union type
     typedef typename F::result_type type;

boost関係でエラーが起こっているのかなと思いましたが、こちらの記事で原因がわかりました。

解決策

原因としてはsync.registerCallback()でかcameraCallbackというメンバ関数を設定しているのですが、このときにthisポインタを渡してあげないといけませんでした。なので、スクリプトの最後の行を下のように変更してあげれば大丈夫です。

sync.registerCallback(&sampleFunction::cameraCallback, this);

thisポインタについて

こちらの記事を参考にして少しthisポインタについて触れておきます。
thisポインタとは、メンバ関数が実行された時のオブジェクトのポインタを指します。thisポインタはメンバ関数内で自分のオブジェクトを操作する時に必要になります。例えば、メンバ関数から他の関数に自分のオブジェクトを渡す時などに使用されます。自分の場合だと、メンバ関数のInit()からcameraCallback()にオブジェクトを渡しているので、thisポインタを渡す必要がありました。

まとめ

thisポインタの存在をすっかり忘れていました。でも、やはりC++は奥深くて面白いなと感じました。

間違いや質問、ご意見等ありましたらお気軽にコメントください。頑張って答えますので(笑)。