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を与えたスレッド
この記述は大変綺麗で一貫性があると思います。が、言語の構文上不可能であることが悔やまれます。