1 Boost.Function
Boost.Function位於 #include <boost/function.hpp>
之中,其提供了類似函數指針的功能。但是這個“函數指針”不但能夠指向普通的函數而且還能夠指向函數對象或者成員函數。我們可以將其當作對函數指針功能的擴展。下面是它的一個使用示例:
#include <iostream>
#include <boost/function.hpp>
struct myStruct
{
int operator ()(const char* str)
{
std::cout<<str<<std::endl;
return 0;
}
};
int main()
{
myStruct mySt;
boost::function<int (const char*)> fPtr;
fPtr = mySt;
fPtr("function object");
fPtr = std::atoi;
std::cout<<fPtr("53")<<std::endl;
}
在這個例子中我們分別給fPtr賦值了一個函數對象和函數,可以看出它們的表現相同。如果我們調用一個沒有賦值的function時,會拋出boost::bad_function_call
異常,當我們給function賦值為0時會釋放其保存的函數,這時候對其的調用同樣會引發上述異常。當我們用function對象來保存一個成員函數時,必須在定義的時候顯示的在第一個輸入指定是那個類,同時在調用的使用第一個參數必須要是類對象的地址,下面是一個調用示例:
#include <iostream>
#include <boost/function.hpp>
struct myStruct
{
void hello(std::ostream & os)
{
os<<"Hello world!"<<std::endl;
}
};
int main()
{
myStruct mySt;
boost::function<void (myStruct*,std::ostream&)> fPtr = &myStruct::hello;
fPtr(&mySt,boost::ref(std::cout));
}
這里我們使用的是指針傳遞,當然對應的也可以使用引用傳遞和值傳遞,這里不過多介紹了,如果想了解可以參考后面提到的參考文章。另外這里使用到了boost::ref用來傳遞不可復制的輸出流的引用,它提供了一個方便的機制向boost::function傳遞引用,當然這里也可以不加。
2 Boost::Lambda
Lambda表達式又稱匿名函數,用來定義一些小的而且無需關心函數名的函數,在這些場合使用Lambda表達式定義函數能夠使得程序看起來更加清晰。但是如果過分的使用lambda表達式又會是程序過於混亂。在使用的過程中必須要根據實際情況進行取舍。lambda表達式的目的是讓源代碼更加緊湊,也更容易理解。首先我們先看一個不使用lambda的一個示例:
#include <iostream>
#include <vector>
#include <algorithm>
void print(int i)
{
std::cout << i << std::endl;
}
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::for_each(v.begin(), v.end(), print);
}
這個例子是用來循環打印向量中的元素。對於這個簡短的打印函數在每次調用的過程中都要想普通函數那樣進棧出棧,十分浪費時間。一個解決辦法是使用inline關鍵字將其聲明為在線函數。但是這還存在一個問題,就是代碼很不緊湊,這個時候我們就可以使用lambda表達式來解決這個問題,使用示例如下:
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/lambda/lambda.hpp>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::for_each(v.begin(), v.end(), std::cout<<boost::lambda::_1<<"\n");
}
這里我們結合lambda表達式和占位符_1
就將上面的函數集成到其調用之處了。boost::lambda
定義了三個占位符,_1,_2,_3
和 boost::bind 不同,它的占位符定義在單獨的命名空間中。boost::lambda很強大但是也有缺點,比如上面最后必須使用\n
而不能使用std::endl
。下面這個例子使用了boost::lambda::if_then()
來輸出大於1的元素。
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/if.hpp>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::for_each(v.begin(), v.end(),boost::lambda::if_then(boost::lambda::_1>1,
std::cout<<boost::lambda::_1<<"\n"));
}
除了boost::lambda::if_then()
,boost.lambda還提供了boost::lambda::if_then_else()
和boost::lambda::if_then_else_return()
模板函數,它們都要求三個參數。另外還提供了用於實現循環、轉換操作符,甚至是throw——允許lambda函數拋出異常的模板。
雖然可以用這些來構造復雜的lambda函數,但我們必須要考慮到代碼的可讀性不能一味地追求代碼的緊湊。有時候動手編寫一個單獨的函數可能是個不錯的選擇。