日記帳だ! with Tux on Libserver

二度目の大改造!! 日記帳…か?を継承し、より柔軟でパワフルなBlogに変身しました。

RSSに対応しています。リンク・コメント・トラックバックは自由にしていただいてほぼ問題ありません。
RSS購読方法、僕のリンク・コメント・トラックバックについての考えを読むことをおすすめします。

JavaScriptを有効にし、Cookieを受け入れ、以下のブラウザを使うことで完全なコンテンツが楽しめます。
Mozilla Firefox 3.0(Get Firefox)・Opera 9.6・Safari 3.2・Lunascape 4/5(Gecko)・Lunascape 5(WebKit)
Internet Explorer 7/8とそれを使うIEコンポーネントブラウザ(Lunascape・Sleipnirなど)

デリゲートだってboost::bindで作る

C++にはデリゲートみたいな便利な仕掛けはない。
実はメソッドのポインタってのはあるんですけど、それの使い方ってこんな風にするんですね。
typedef int(Hoge::*MethodPtr)(int);
MethodPtr p=&Hoge::Plus;
myhoge->*p(10);
正直めんどくさいですね。
それにあんまり使いやすいとは言えない。
けどまだこういう仕組みがあるだけましです。工夫したら便利になるんですから。
例によってBoostです。
#include <iostream>
#include <vector>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/ref.hpp>
class Hoge{
private:
int _x;
public:
Hoge(int x) { this->_x=x; }
int Mul (int y){ return y*this->_x; }
int Plus(int y){ return y+this->_x; }
};
class Boke{
private:
std::string _x;
public:
Boke(const char* xbase) : _x(xbase) {}
int CodeAt(int i){ return (int)this->_x.at(i); }
};
int Negative(int x){ return -x; }
void main(void){
typedef boost::function<int(int)> DType;
std::vector<DType> delegates;
Hoge myhoge1(10);
delegates.push_back( boost::bind(&Hoge::Mul,boost::ref(myhoge1),_1) );
Hoge myhoge2(80);
delegates.push_back( boost::bind(&Hoge::Plus,boost::ref(myhoge2),_1) );
Boke myboke("0123456789A");
delegates.push_back( boost::bind(&Boke::CodeAt,boost::ref(myboke),_1) );
delegates.push_back( &Negative );
BOOST_FOREACH(DType &cur,delegates){
std::cout << cur(10) << std::endl;
}
}
まず、HogeクラスとBokeクラスを用意してみました。
HogeクラスはPlusメソッドとMulメソッドがあって、それぞれ登録されている値に足したりかけたりした値を返すと。
Bokeクラスは何番目かの文字の文字コードを返すCodeAtメソッド、
あとただの関数のNegative関数。この4つのメソッド・関数を使って話をする。
C#ではデリゲートってのはこんな風に書けた。
Func<int,int> f1=myhoge1.Mul;
こんな風にただの関数ポインタの取り扱いみたいにできたわけだ。
ありがたいけど、C++にはそんな仕組みはない。
そこでそのへんをラップしてくれる関数オブジェクトを作りたいが、それは難しい。
そこでboost::bindっていうやつを使います。
boost::bind(&Hoge::Mul,boost::ref(myhoge1),_1)
bindってのは引数を束縛するって意味。
&Hoge::Mulっていう関数ポインタに引数を束縛すると。
ただこれの使い方は始めに書いたようにmyhoge->*p(10);のように使うわけだな。
そうなったらmyhogeに相当する部分はどうやって指定するのかっていう疑問はあるわな。
なんとboost::bindはそのmyhogeに相当する部分を第一引数と読み替えてくれるらしい。
それで、あとは穴埋め問題みたいに引数に_1、_2としていけば関数オブジェクトのできあがり。
上の例では、&Hoge::Mulの第一引数にmyhoge1を、第二引数に_1を束縛している。
_1ってのは新しく作られた関数オブジェクトの第一引数って意味ね。
myhoge1をboost::refで包んで渡しているけど、参照渡しするときには必要なんです。
あと受ける型ですが、いろいろ考えるのはめんどくさいのでboost::function<int(int)>なんて型を使うと便利。
こんな調子で、引数にintをとり返り値にintが来る点以外では共通点のない関数たちを、
vectorに投げ込んでみた。あとは分け隔て無く使えます。
すごいですね。
C#のデリゲートも同じようなものですけど、まさかこれがC++でもできるとはね。
いやいやBoostすごいですね。
賢すぎると思います。
ただ残念なのはラムダ式の能力は弱すぎることですね。というか無理しすぎ。
C++0xで入るという話だからそれまでは使えませんね。
ラムダ式があればさっきみたいなことを簡単に書けますよね。
Func<int,int> f1= (x)=>myhoge1.Mul(x);
C#ならこんな風に書けます。普通にデリゲート使えよっていう感じですけど。
実はboostはこんなことを自分で考えて作っているんですね。
一体どれだけのことをコンパイラにやらせてるんだってのはあります。
まぁその点で言えばC#も相当ですけど。
こんな仕組みがないのでなかなか読みにくいですけど、boost::bindはわりとわかりやすい方だと思うので、
実践してみるといいと思いますよ。
Author : hidemaro
Date : 2009/05/07(Thu) 23:33
C・C++ | Comment | trackback (0)

Tools