Boost.Lambda 的確是一個好東西,用來舉例最多的恐怕就是這個了:
using namespace boost::lambda;
std::vector<int> v;
// init values
std::for_each(v.begin(), v.end(), std::cout << _1 << ' ');
精緻、優雅、易於理解,下面是一個更漂亮的例子:
std::map<int, int> values;
// init values
std::for_each(values.begin(), values.end(),
std::cout << bind(&std::map<int,int>::value_type::first, _1) << '/t'
<< bind(&std::map<int,int>::value_type::second, _1) << '/n'
);
它將把一個 map 列印成表格形式,其中的 bind 是 boost::lambda::bind,而不是 boost::bind。
看起來都是那麼的輕易,但是我在下面的代碼上卻遇到了麻煩:
std::map<int,int>::iterator iter =
bind(&std::map<int,int>::find, &values, _1)(boost::cref(1));
任我使盡渾身解數,它還是沒能編譯成功,要知道這種情況經常給出幾公裡長的出錯資訊,要從中瞭解問題的癥結幾乎不太可能。然而,下面這一句非常相似的卻成功運行:
std::cout << bind(&std::map<int,int>::count, &values, _1)(boost::cref(1));
一個是 bind 到 find,一個是 bind 到 count ,它們有什麼區別呢?看看 STL(VC7.1) 的實現就發現,find 有兩個版本:const 和 mutable ,而 count 只有一個版本。
難道是 Boost.Lambda 在遇到 constness 重載的時候出了問題?驗證一下:
class A
{
int i, j;
public:
int& I()
{ return i; }
const int& I()const
{ return i; }
int J()
{ return j; }
}a;
//.......
std::cout << bind(&A::I, _1)(a);
果然不假,上面的代碼編譯的時候給出類似的錯誤資訊,而下面這一句則沒有問題:
std::cout << bind(&A::J, _1)(a);
然而,如果換用 Boost.Bind ,則在兩種情況下都可以正確運行,包括上面所說的 count 和 find 。不過,最妙的是只要拿掉
using namespace boost::lambda;
而改用
using namespace boost;
那麼同樣的代碼無需修改就可以運行了。
我還沒有仔細看 Boost.Lambda 的代碼來確定到底發生了什麼,但是 C++0x 標準並沒有接納 lambda,可能也和這些實現上的問題有關吧。