boost::thread

Boost::threadのコンストラクタは中々ピーキーだなぁと思った。
まず次のようなコードはエラーになる

class A{
public:
  void f(int x){
    std::cerr << x << std::endl;
  }
  void A(){
    boost::thread th(&A::f, 1); //Boost 1.36以上だと、boost::bindは要らない
  }
};

int main(void){
  A a;
}

これがエラーになる理由は、クラスAのメンバ関数fがstaticでないから。なのでこういうのは通る。

class A{
public:
  static void f(int x){
    std::cerr << x << std::endl;
  }
  void A(){
    boost::thread th(&A::f, 1);
  }
};

int main(void){
  A a;
}

しかしstatic関数でないこともしたい。例えば次。

class A{
public:
  int x;
  void f(void){
    std::cerr << x << std::endl;
  }
  void A(int x): x(x){
    boost::thread th(&A::f);
  }
};

int main(void){
  A a(7);
}

当然これはコンパイルが通らない。ここでピーキーな仕様が出てくる。こういうstatic関数でない関数を使ってthreadを生成する場合、次のようにオブジェクトを渡すと良いらしい。通常、threadのコンストラクタは、関数ポインタ+関数引数列と解釈されるので、この仕様がどうにも一貫性がない。

class A{
public:
  int x;
  void f(){
    std::cerr << x << std::endl;
  }
  void A(int x): x(x){
    boost::thread th(&A::f, this);
  }
};

int main(void){
  A a(7);
}

===※追記
boost 1.36以降の、boost::threadのコンストラクタは、boost::bindでラップされてる。なので、普通はコンストラクタの引数は、

boost::thread th(f, arg1, arg2) = f(arg1,arg2) のスレッド 

と解釈される。そこで、非staticメソッドをスレッドにする場合を考えると、

boost::thread th(f, arg1, obj) = f(arg1,obj) のスレッド 

とはならず、

boost::thread th(f, arg1, obj) = obj.f(arg1) のスレッド 

となる。仮に「boost::bindは第1引数のオブジェクトと、その他のオブジェクトを紐付けるという意味だ」と解釈するとしよう。しかしその場合、

boost::thread th(f, arg1, arg2) = arg1,arg2が適切にfへ紐付けされたスレッド 

となるべきなので、arg1,arg2を書く順番は任意で良いはず。だがそうはならない(当たり前だけど)。この一貫性のなさが美しくなく、「場合によって使い分ける仕様」=ピーキーだなと思う。
まあ、どうしてこうなってしまったのかは簡単に想像は付くのですがね……


コメント欄で頂いたもので、もし次の用にかけたら良いのにという意見がありました。

boost::thread th(obj.f(arg1,arg2)) = objのメソッドfにarg1とarg2を与えたスレッド 

この記述は大変綺麗で一貫性があると思います。が、言語の構文上不可能であることが悔やまれます。