decltypeでboost::bindに渡すファンクタの戻り値を指定できないか頑張る(conceptGCC)

boost::bindは、ファンクタを渡した場合に戻り値の推測することができないので、
std::function系を継承してないファンクタを渡す場合は下のようにファンクタの中で戻り値をresult_typeとしてtypedefするか

#include <iostream>
#include <string>
#include <boost/bind.hpp>

struct Functor
{
	typedef void result_type;

	result_type operator()(std::string str){
		std::cout << str << std::endl;
	}
};


int main()
{
	boost::bind(Functor(),"Hello")();

	return 0;
}

下のようにテンプレート引数として渡す必要がある

int main()
{
	boost::bind<void>(Functor(),"Hello")();

	return 0;
}


まあ、std::function系をちゃんと継承するのであれば

#include <iostream>
#include <string>
#include <functional>
#include <boost/bind.hpp>

struct Functor : std::unary_function< std::string , void >
{
	result_type operator()(argument_type str){
		std::cout << str << std::endl;
	}
};


int main()
{
	boost::bind(Functor(),"Hello")();

	return 0;
}

こんな感じにもできる



conceptGCCでdecltypeが使えるようなので、
decltypeを使って上手いこと書けないかやってみると

#include <iostream>
#include <string>
#include <boost/bind.hpp>

struct Functor
{
	void operator()(std::string str){
		std::cout << str << std::endl;
	}
};


int main()
{
	boost::bind<decltype(Functor()(std::string()))>(Functor(),"Hello")();

	return 0;
}

とりあえずこれで動いた
でもこれだとコーディング量が増えただけなような・・・



result_typeを上手いことdecltypeを使って定義してやれないかいろいろ試したんだけど、なかなか上手くいかず
引数のないファンクタならとりあえず動きそうな物が出来た↓

#include <iostream>
#include <string>
#include <boost/bind.hpp>

struct SayHello
{
	void operator()(){
		std::cout << "Hello" << std::endl;
	}
};

template <typename Functor>
struct FunctorWrapper
{
	typedef decltype(Functor()()) result_type;

	void operator()(){
		Functor()();
	}
};

int main()
{
	boost::bind(FunctorWrapper<SayHello>())();//バインドする引数もないのにバインド

	return 0;
}

すごい、何の役にも立たない!
なんか確実に上手いことやる方法はあるんだろうけどなー


ということで、Modern C++ Designがすごく読みたいです。

Qt 4.5のビルド

Qt 4.5がリリースされたのでVCでビルド


4.5からライセンスがLGPLになったので、普通はdynamicLinkするんだろうけど
人に実行ファイルを渡すときになかなか面倒なのでstaticでビルド

configure -debug-and-release -no-qt3support -static -D _CRT_SECURE_NO_WARNINGS

が、上手くいかない。。

        lib /NOLOGO  /OUT:..\..\..\..\lib\QtWebKit.lib @C:\Users\val\AppData\
Local\Temp\nmA187.tmp
QtWebKit_pch.obj : MSIL .netmodule または /GL を伴ってコンパイルされたモジュール
が見つかりました。/LTCG を使用して再開始してください。リンカのパフォーマンスを向
上させるためには、コマンドラインに /LTCG を追加してください。
..\..\..\..\lib\QtWebKit.lib : fatal error LNK1106: ファイルが無効であるか、また
はディスクがいっぱいです: 0x5834AD6C にシークできません。
NMAKE : fatal error U1077: '"c:\Program Files\Microsoft Visual Studio 9.0\VC\BIN
\lib.EXE"' : リターン コード '0x452'
Stop.
NMAKE : fatal error U1077: '"c:\Program Files\Microsoft Visual Studio 9.0\VC\BIN
\nmake.exe"' : リターン コード '0x2'
Stop.
NMAKE : fatal error U1077: 'cd' : リターン コード '0x2'
Stop.


LINK1106でぐぐってみると
http://support.microsoft.com/kb/888326/
しかしこれに書いてあるとおりにやっても通らない


もうちょっと探してみると
http://lists.trolltech.com/pipermail/qt4-preview-feedback/2008-December/000252.html
これによると、WebKitのバグで同じようなのあるけどそれより前のバージョンのWebKit使ってるんじゃない?ってことらしい
しかしこんなに古いバージョン(r35629)をQtが使ってるとも思えないというか
VERSIONファイルを見てみても明らかにそれより後のバージョンなんだよな・・・(WebKitのフォルダにVERSIONファイルがいくつもあるのでいまいちよくわからない


いろいろ試したんだけど上手くいかないので結局dynamicでビルド


Qt4.5については、更新履歴によると主なものとしてはMacの64bit環境対応と、WebKitのバージョンアップみたいなので
正直あまり自分には関係ないっぽい(LGPLにはなったけど


むしろQt for s60向けのベータ版が「Garden」にバージョンアップしてたのが気になるので
これは後で試してみる(N82でサンプルは動いた、PC側の環境構築はまだ


とりあえずいままでVCLIBで作ってたソフトがちゃんとリンクできなくなったので、それを解決するとしよう

次期CiNii試験公開

論文検索でいろいろとお世話になっているCiNiiの次期バージョンが試験公開されたみたい


http://ciexam.nii.ac.jp/
http://codezine.jp/article/detail/3683


OpenSearchに対応したりいろいろしてるので
自分用の検索アプリケーションを作ったりするのが楽になるのかも



あの手の論文検索ってあんまりUIとか考えてない&改善する気もないと思ってたからちょっと意外だった

VS2010CTP (VC10) でBoostをビルド

いつも通りbjam(3.1.17)を使ってビルドしようとしたら、どうやらmsvcのバージョン自動識別に失敗していて(たぶんbjamがVC10にまだ対応してない)
上手くいかなかった。

生成されたライブラリファイルを見ると、本来ならないといけない
libboost_filesystem-vc100-mt-gd-1_38.lib
ではなく
libboost_filesystem-vc-mt-gd-1_38.lib
と、ファイル名からバージョンの部分が抜け落ちているっぽい


そこで、bjamのオプションとして
 --toolset=msvc
ではなく、
 --toolset=msvc-10.0
と明示的に指定してやれば動いた。


もうビルドしてもう一回やるのはいやだよ! って場合には、
boost(1.38.0)の
boost/config/auto_link.hppを

//auto_link.hpp

145:	// vc10:
146:	//#  define BOOST_LIB_TOOLSET "vc100"
147:	#  define BOOST_LIB_TOOLSET "vc"

と書き換えるととりあえず大丈夫なはず(実は先にたどり着いたのはこっち)


ちょっと使ってみたけどインテリセンスが良くなったってのは本当みたい
少なくともboost::bindを通過した後沈黙したりはしなくなってるな。

VS2010 CTPのアクティベーション

たしか2008年の11月ぐらいに公開されたVisua Studio 2010のCTP版
VM用サーバの設定もある程度済んできたのでまともに使おうと思ってセットアップしてみた
でもなかなかうまくいかなかった


とりあえず上手くいくまでに失敗したことを振り返る


やりたかったこと:配布されているVPCのイメージをVMWare用に変換してVMWareServer上で動かす
とりあえずイメージはvCenter Converterで変換できたが、パフォーマンスが全く出ない、vToolsのマウスドライバを入れるとポインタが消失するなどいろいろと問題が。
パフォーマンスに関しては自分がいろいろやってしまったのが原因かも知れないけど(割り当てCPU数を2コアに変更したり)
いろいろいじったら↓のように、2*4.687GHzになったり、仮想マシンモニターだとCPU負荷が3%なのにゲスト側からだと100%に見える、不明なデバイスがいろいろと出現する、などいろいろと問題続き。


なんだか試行錯誤しても上手く行く気がしなかったのであきらめてVirtualPC上で使うことにした
といっても、リモートから使えないと困るので、PacatixVPNのLANカードをブリッジで追加しておいた。
これだと、普段はサーバ側でVirtualPCのCTPVMをずっと稼働させておけば、ノートPCからワークグループでCTPVMが見えるので、
リモート接続で繋げばVMWareServer Remote Console的な事ができるということで(というかこの方法の方がいろいろと楽)
で、VirtualPC上でVMに既にセットアップされているWindows Server 2008にログインして、VS2010を起動すると「使用期限が切れているから買ってね!」
みたいなお知らせが出て起動できず、VMをリブートしたら今度はOSそのもののアクティベーションにひっかかってログインもできなくなった。もうつかれたよ。
アクティベーションの問題に関しては、MSのCTPダウンロードのページのRelated Resourceのところに
回避法がきちんと載っているページがあったので、とりあえずそこを参照しながら作業。(どうやら2009年度になるとまずいらしい)
割と一箇所でも間違えると最初からやり直しが多い感じだったので、今度セットアップするときのために以下メモ書き


1.CTPをダウンロードして展開すると、vmcとvhdが出てくるのでコピーして作業とRawの物を分ける(ここで元のイメージを残しておくとミスったとき楽)
2.VirtualPCのホストとゲストの時刻同期を止めるために、以下のようにvmcファイルに追記する

<integration> 
	<microsoft> 
        		<mouse> 
            			<allow type="boolean">true</allow> 
        		</mouse> 
		//ここから追加
        		<components> 
            			<host_time_sync> 
                				<enabled type="boolean">false</enabled> 
            			</host_time_sync> 
        		</components> 
		//ここまで追加
    	</microsoft> 
</integration>

3.起動したら、TFSSetupでログインする
ちなみに設定されているパスワード一覧をMSのサイトから引用
Administrator: TFSSETUP, password: 1Setuptfs (use this account to explore the CTP)
Administrator: Administrator,password: P2ssw0rd
User: TFSREPORTS, password: 1Reports
User: TFSSERVICE, password: 1Service
4.ログインしたらすかさず、インターネット時刻の同期を止めて、日付を過去に戻す(戻しすぎると駄目、たぶんCTP配布開始から2008/12/31の間なら大丈夫)
5.キーボードが英語なので、デバイスマネージャーからドライバのアップデートで106/109 with Eisuuに変更する
6.リブートした後、コントロールパネルのローカライズオプションから、入力メソッドをJPIMEに変更する
7.ここで初めてVS2010を立ち上げて、特に期限切れのポップアップなどが出なければ成功


注意点としては、たぶんリブートしたときにOSのアクティベーションに引っかかることがあること。
これは、秒数のカウントダウンが0になるまで待って、グレーアウトが解除されたActivate Laterを押せばログインできる。
上手くいかない場合は最初にバックアップを取ったイメージで最初からやりなおす。



しかしMSが公式にアクティベーション回避するためにシステム時刻をいじるとかリリース出してるのはちょっとアレな気がする

VMWareServerの設定

ちょっとVMWareServerの設定をいろいろやったのでメモ




その1 仮想マシンとホストのPacatixVPNの仮想LANカードにブリッジする

まず、ネットワーク接続のvmnetと適当にブリッジしてやったら落ちた


ということでちゃんと調べてみるとどうやらvmwareのネットワークは
vmnet0:ブリッジ用
vmnet1:ホストオンリー(ホスト上の仮想プライベートネットワークとして動作)
vmnet8:nat用
となっていて、なにか別の用途で使いたい場合は、自分でvmnet2~7の間で行えばいいらしい


自分の環境のvmwareServer2.0だと
"C:\Program Files\VMware\VMware Server\vmnetcfg.exe"
にvmnetの設定ツールがあったので、
vmnet2を新規追加して、ブリッジインターフェイスが自動選択になっていたvmnet0を物理LANカードとのブリッジ、
新しく追加したvmnet2をpacatixの仮想LANカードとのブリッジとして、
仮想マシンにネットワークインターフェイスとしてvmnet2を追加したら
仮想マシン側からpacatixVPNのワークグループが見えるようになった。




その2 vmwareServer2.0のwebインターフェイスfirefoxから使う


普通にアクセスするとオレオレ証明書で弾かれてしまうので、
オプション→詳細→証明書を表示→サーバ証明書→例外を追加
から、例外として登録すればOK


なんかぐぐったかんじだと弾かれた段階で「例外を追加しますか?」ってページが出るはずなんだけど
自分の環境だとただ白いページになってしまったのでとりあえずメモ




その3 VirtualPC形式(vhd,vmc)をvmwareServer2.0で使えるよう(vhdk,vmx)に変換する


とりあえず目標は、この前まともに起動しなくなったVisualStudio2010 CTPのVMを作り直すこと


前回作業したときは
vhdをvmdkにするのにNHC
vmxを作るのにvmx-makerを使ったんだけど
VirtualHardwareのバージョンを上げるとまともに動かなくなったりといろいろ問題があったので、
今回は何か別の方法を探すことに


というかこんな用途は本家vmware側も想定済みだろうから純正を探してみたらあった
VMware vCenter Converter
これで.vmcを指定してやると、vhdkへの変換なども全部やってくれるのですごく便利
VirtualHardwareも最初からver7だったので特に問題なし

混入スタイルの基底クラス

この前Effective C++を読み返していると、テンプレート引数をクラス定義で使っていないのに、
テンプレートクラスになっている物があったので、いろいろ考えた結果、
派生クラス作成時に派生クラス名をテンプレート引数として渡すことによって、
基底クラスを別のものにするために使ってるんじゃないかという結論に


ということで、とりあえず一度サンプルを書いてためしてみた

#include <iostream>
#include <vector>

struct Base
{
	static int baseCount;
	Base(){baseCount++;}
	Base(const Base& rhs){baseCount++;}
	~Base(){baseCount--;}
};

template<class T>
struct TemplateBase
{
	static int templateBaseCount;
	TemplateBase(){templateBaseCount++;}
	TemplateBase(const TemplateBase& rhs){templateBaseCount++;}
	~TemplateBase(){templateBaseCount--;}
};

struct Derived1 : public TemplateBase<Derived1> , public Base
{
	static int der1Count;
	Derived1(){der1Count++;}
	Derived1(const Derived1& rhs){der1Count++;}
	~Derived1(){der1Count--;}
};

struct Derived2 : public TemplateBase<Derived2> , public Base
{
	static int der2Count;
	Derived2(){der2Count++;}
	Derived2(const Derived2& rhs){der2Count++;}
	~Derived2(){der2Count--;}
};

int TemplateBase<Derived1>::templateBaseCount = 0;
int TemplateBase<Derived2>::templateBaseCount = 0;
int Base::baseCount = 0;
int Derived1::der1Count = 0;
int Derived2::der2Count = 0;

int main()
{
	std::vector<Derived1> der1Vec(10);
	std::vector<Derived2> der2Vec(20);

	std::cout << "BaseCount:" << Base::baseCount << std::endl;
	std::cout << "templateBase<Derived1>Count:" << TemplateBase<Derived1>::templateBaseCount << std::endl;
	std::cout << "templateBase<Derived2>Count:" << TemplateBase<Derived2>::templateBaseCount << std::endl;
	std::cout << "Der1Count:" << Derived1::der1Count << std::endl;
	std::cout << "der2Count:" << Derived2::der2Count << std::endl;
}

実行結果:
BaseCount:30
templateBaseCount:10
templateBaseCount:20
Der1Count:10
der2Count:20
結果を見ると、確かにstaticメンバーが共有されていないので、別の基底クラスから継承したのと同じような効果になっているのがわかる。


まあ

int TemplateBase<Derived1>::templateBaseCount = 0;
int TemplateBase<Derived2>::templateBaseCount = 0;
int Base::baseCount = 0;
int Derived1::der1Count = 0;
int Derived2::der2Count = 0;

で、テンプレート引数毎に初期化しなければいけない時点で大体わかってたことなんだけど。


その後、調べてみると、こういった手法を混入スタイルとか呼ぶらしい
今回の例だと単純に基底クラスを分離するためだけに使っているけれど
こういったかんじの派生クラス名を基底クラスのテンプレートパラメーターにする手法は
他にもいろいろ使い道があるようなので、ちょっと調べてみることとしよう。