Entries

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

あいまいが足りない

タグ: C++ Boost
#include <boost/bind.hpp>

#include <boost/lambda/bind.hpp>

を同時にインクルードして使おうとすると、何かと面倒な事態にぶち当たる。
代表的なのは、互いに同じ名前のプレースホルダを使うことによる

error C2872: '_1' : あいまいなシンボルです。

だが、これはまだエラーになってくれるだけまし。
むしろ「このエラーを期待してコンパイルしたのに通ってしまった時」がヤバイ。
「いつの間にかこの問題は解決されていたのか!」などと喜んではならない。

#include <iostream>
#include <boost/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/function.hpp>

void bar(int* n)
{
	*n = 2;
}

void baz(int* n)
{
	std::cout << *n << std::endl;
}

template <typename Function>
void foo(Function f)
{
	int n = 1;
	f(&n);
}

namespace {

void hoge()
{
	using namespace boost::lambda;
	foo(bind(&baz, (bind(&bar, _1), _1)));
}

} // unnamed

int main(int, char*[])
{
	hoge();
	return 0;
}

関数hogeは次のような処理が行われることを期待する。

int n = 1;
bar(&n); // n = 2
baz(&n); // n を出力

よって標準出力には「2」が出力されるはず。

ところが実際に出力される数字は「1」。
Boost 1.35でも1.36でも、このコードでは関数fooは呼ばれない。
何故か。

直接の原因は「グローバルの無名名前空間(という呼び方で良いのだろうか)の関数内で、修飾のない _1 を使っている」こと。
_1`anonymous-namespace'::_1boost::lambda::`anonymous-namespace'::_1 の2つが定義されており、 fuga のスコープでは using namespace boost::lambda をしても前者が優先される。
`anonymous-namespace'::_1 の関連名前空間は boost であり(ADL)、且つ bind の第1引数 &foo が「boost名前空間(Boost.Bind)では特殊化されているがboost::lambda名前空間(Boost.Lambad)では特殊化されていない関数ポインタ」であることから、 bindboost::bind が選ばれる。
bindboost::bind になるということは (bind(&foo, _1), _1) はラムダ式には成らず、ただのカンマ演算として処理されて (_1)
その結果

foo(bind(&baz, (bind(&bar, _1), _1)));

の行は

foo(bind(&baz, _1));

となり、barの呼び出しが消滅してしまうことになったのである。

スポンサーサイト

コメント

コメントの投稿

コメントの投稿
管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://idlysphere.blog66.fc2.com/tb.php/139-c3810660
この記事にトラックバックする(FC2ブログユーザー)

Appendix

タグ

Blog内検索

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。