...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

Policyをboost::function+boost:bindで

前はpolicyでやってたのだが,いちいちオブジェクトを作る作業が大仰すぎると感じた.
そこでメンバ関数ポインタを使ってみた.

Policyをメンバ関数ポインタで - ...ing logging 3.0

の続き.


メンバ関数ポインタは型がややこしいから嫌だった.
delegateがあればいいのに・・・と思ってたら,とあることを思い出した.
そうだ,boost::function+boost::bindがあった.

#include <iostream>
using namespace std;

#include <boost/function.hpp>
#include <boost/bind.hpp>
using namespace boost;

// 本来はどこかで定義されているものたち
typedef int HWND;
void MouseCapture(HWND){}
void ReleaseCapture(){}
HWND GetHWnd(){return 0;}

class mouse_event_logger {
public:
  void on_left_button_down(){cout << "LeftButtonDown" << endl;}
  void on_left_button_up(){cout << "LeftButtonUp" << endl;}
  void on_right_button_down(){cout << "RightButtonDown" << endl;}
  void on_right_button_up(){cout << "RightButtonUp" << endl;}
  //...
};

void f(function<void()> mouse_capture, function<void()> logger_method, bool enabled)
{
  mouse_capture();
  if (enabled)
    logger_method();
};

class context {
  bool enabled;
  mouse_event_logger logger;
public:
  context() : enabled(false) {}
  void set_enabled(bool b) {enabled = b;}

  // 同じようなメソッドがたくさん出てくるのでまとめたいけれど
  // 型の違いではないからtemplateではうまくまとめられない?
  void on_left_button_down(HWND hwnd) {
    ::MouseCapture(hwnd);
    if (enabled)
      logger.on_left_button_down();
  }
  void on_left_button_up() {
    ::ReleaseCapture();
    if (enabled)
      logger.on_left_button_up();
  }

  // こうだ!
  void on_right_button_down(HWND hwnd) {
    f(bind(::MouseCapture, hwnd), bind(&mouse_event_logger::on_right_button_down, &logger), enabled);
  }
  void on_right_button_up() {
    f(::ReleaseCapture, bind(&mouse_event_logger::on_right_button_up, &logger), enabled);
  }
};

int main()
{
  context c;
  c.set_enabled(true);
  c.on_left_button_down(GetHWnd());
  c.on_left_button_up();
  c.on_right_button_down(GetHWnd());
  c.on_right_button_up();
  return 0;
}

ReleaseCaptureHelper()も自然になくなった.
心配なのは実行速度くらい.
最適化で展開されたりするのかな.

追記

ちなみにオブジェクトを作る作業が大仰というのは,クラスを定義することも含めての話.