本文根據boost的教程整理。
主要介紹boost function對象的用法。
boost function
boost function是什麼
boost function是一組類和模板組合,用於包裝各種函數。從功能上,它類似於函數指針,但是比函數指針的功能更強大。
使用boost function,必須包含頭文件
[cpp] #include <boost/function.hpp>
#include <boost/function.hpp>
除了頭文件外,不需要額外的庫。
注意,boost function有兩種形式:一種為推薦形式;另外一種為可移植形式。推薦形式的語法更加簡潔;可移植形式的可移植性好,但是語法羅嗦。由於目前的gcc/vc的版本都已經能夠使用推薦形式了,因此,可移植形式就不在描述。有興趣的可以參閱boost相關文檔。
boost function 基本用法
例如,有一個函數
[cpp] float int_div(int x, int y)
{
return ((float)x)/y;
}
float int_div(int x, int y)
{
return ((float)x)/y;
}
我們可以這樣使用
[cpp] oost::function<float (int x, int y)> f;
f = int_div;
std::cout<< f(5,3) << std::endl;
boost::function<float (int x, int y)> f;
f = int_div;
std::cout<< f(5,3) << std::endl;
可以看到,它的用法和函數指針很相似的。
當然,boost::function不止這些,請看下面的函數對象:
[cpp] struct int_add {
float operator()(int x, int y) {
return (float)(x + y);
}
};
struct int_add {
float operator()(int x, int y) {
return (float)(x + y);
}
};
上面的 boost::function<float (int x, int y)> f 聲明的f對象,仍舊可以保存int_add:
[cpp] f = int_add();
std::cout << "f add : "<< f(10,20) << std::endl;
f = int_add();
std::cout << "f add : "<< f(10,20) << std::endl;
另外,boost::function還可以用來判斷函數是否為空
[cpp] f(f)
std::cout << " f is ok!"<< std::endl;
if(f)
std::cout << " f is ok!"<< std::endl;
要清空f,可以使用
[cpp] f = 0;
if(!f)
std::cout << "f is cleard!" << std::endl;
f = 0;
if(!f)
std::cout << "f is cleard!" << std::endl;
針對成員函數
成員函數,也可以被綁定,如有類
[cpp] struct X {
int foo(int x) {
std::cout << "X " << this << " foo x="<<x << std::endl;
return x + 100;
};
};
struct X {
int foo(int x) {
std::cout << "X " << this << " foo x="<<x << std::endl;
return x + 100;
};
};
可以這樣使用
[cpp] boost::function<int (X*, int)> mf;
mf = &X::foo;
X x;
mf(&x, 5);
boost::function<int (X*, int)> mf;
mf = &X::foo;
X x;
mf(&x, 5);
和bind同時使用
在需要包裝參數的場合,我們可以配合boost::bind一起使用。
首先,加入boost::bind的頭文件
[cpp] #include <boost/bind.hpp>
#include <boost/bind.hpp>
這樣使用
[cpp] boost::function<int (int)> mbf;
mbf = bind(&X::foo, &x, _1);
mbf(10);
boost::function<int (int)> mbf;
mbf = bind(&X::foo, &x, _1);
mbf(10);
bind將x的指針保存在function對象中。
function factory
function factory是一個封裝類工廠的模板。它有兩種,一種是value_factory,一種是factory。
[cpp]
boost::factory<T*>()(arg1,arg2,arg3)
// same as new T(arg1,arg2,arg3)
boost::value_factory<T>()(arg1,arg2,arg3)
// same as T(arg1,arg2,arg3)
boost::factory<T*>()(arg1,arg2,arg3)
// same as new T(arg1,arg2,arg3)
boost::value_factory<T>()(arg1,arg2,arg3)
// same as T(arg1,arg2,arg3)
使用function factory的原因
我們考慮這樣的場景:使用抽象工廠模式,有一個接口,有若干個實現,通常的做法是這樣的:
[cpp]
//聲明接口
class Interface
{
public:
virtual void print(int a) = 0; //接口函數
};
//聲明抽象工廠
class Interface_Factory {
public:
virtual Interface * create() = 0;
};
//聲明接口
class Interface
{
public:
virtual void print(int a) = 0; //接口函數
};
//聲明抽象工廠
class Interface_Factory {
public:
virtual Interface * create() = 0;
};
然後,我們有若干個實現
[cpp]
class ImplA : public Interface
{
public:
virtual void print(int a) {
std::cout << "== A == a=" << a << std::endl;
}
};
//提供ImplA的類工廠
class ImplA_Factory : public Interface_Factory
{
public:
Interface * create() { return new ImplA(); }
static ImplA_Factory _implAFactory;
};
ImplA_Factory ImplA_Factory::_implAFactory;
//同理,ImplB的實現
class ImplB : public Interface
{
public:
virtual void print(int a) {
std::cout << "== B == a=" << a << std::endl;
}
};
//提供ImplB的類工廠
class ImplB_Factory : public Interface_Factory
{
public:
Interface * create() { return new ImplB(); }
static ImplB_Factory _implBFactory;
};
ImplB_Factory ImplB_Factory::_implBFactory;
class ImplA : public Interface
{
public:
virtual void print(int a) {
std::cout << "== A == a=" << a << std::endl;
}
};
//提供ImplA的類工廠
class ImplA_Factory : public Interface_Factory
{
public:
Interface * create() { return new ImplA(); }
static ImplA_Factory _implAFactory;
};
ImplA_Factory ImplA_Factory::_implAFactory;
//同理,ImplB的實現
class ImplB : public Interface
{
public:
virtual void print(int a) {
std::cout << "== B == a=" << a << std::endl;
}
};
//提供ImplB的類工廠
class ImplB_Factory : public Interface_Factory
{
public:
Interface * create() { return new ImplB(); }
static ImplB_Factory _implBFactory;
};
ImplB_Factory ImplB_Factory::_implBFactory;
如果你要使用它,就需要這些寫
[cpp]
std::map<std::string, Interface_Factory*> factories;
int main()
{
factories["A"] = &ImplA_Factory::_implAFactory;
factories["B"] = &ImplB_Factory::_implBFactory;
.....
}
std::map<std::string, Interface_Factory*> factories;
int main()
{
factories["A"] = &ImplA_Factory::_implAFactory;
factories["B"] = &ImplB_Factory::_implBFactory;
.....
}
如果仔細觀察下,就會發現,實際上,ImplA_Factory和ImplB_Factory的內容幾乎都一樣。但是卻寫了不少重復性的代碼。factory就是解決該問題的。
factory的解決之道
使用boost::factory,是完全不需要定義Interface_Factory接口和對應的實現的,我們定義一個boost::function對象,替代Interface_Factory
[cpp]
typedef boost::function< I *() > I_factory; //替代Interface_Factory的定義
typedef boost::function< I *() > I_factory; //替代Interface_Factory的定義用boost::factory替代ImplA_Factory和ImplB_Factory:
[cpp]
std::map<std::string, I_factory> factories;
....
factories["A"] = boost::factory<ImplA*> (); //等價於 &ImplA_Factory::_ImplAFactory;
factories["B"] = boost::factory<ImplB*> (); //等價於 &ImplB_Factory::_ImplBFactory;
std::map<std::string, I_factory> factories;
....
factories["A"] = boost::factory<ImplA*> (); //等價於 &ImplA_Factory::_ImplAFactory;
factories["B"] = boost::factory<ImplB*> (); //等價於 &ImplB_Factory::_ImplBFactory;
在使用的時候,與普通方法絲毫不差,如
[cpp]
void run_interface(const char* name)
{
I_factory factory = factories[name];
if(!factory)
{
std::cout<<"factory " << name << " is not exist" << std::endl;
return;
}
I *i = factory();
i->print(100);
delete i;
}
void run_interface(const char* name)
{
I_factory factory = factories[name];
if(!factory)
{
std::cout<<"factory " << name << " is not exist" << std::endl;
return;
}
I *i = factory();
i->print(100);
delete i;
}
通過判斷factory的函數是否為空,就可以知道對應的類實現是否存在。我們可以這樣簡單的使用
[cpp]
run_interface("A");
run_interface("B");
run_interface("C");
run_interface("A");
run_interface("B");
run_interface("C");由於"C"對象不存在,因此,將打印 "factory C is not exist"的信息。
OverloadedFunction
考慮下面的代碼
[cpp]
const std::string& identity_s(const std::string& x) // Function (as pointer).
{ return x; }
int identity_i_impl(int x) { return x; }
int (&identity_i)(int) = identity_i_impl; // Function reference.
double identity_d_impl(double x) { return x; }
boost::function<double (double)> identity_d = identity_d_impl; // Functor.
const std::string& identity_s(const std::string& x) // Function (as pointer).
{ return x; }
int identity_i_impl(int x) { return x; }
int (&identity_i)(int) = identity_i_impl; // Function reference.
double identity_d_impl(double x) { return x; }
boost::function<double (double)> identity_d = identity_d_impl; // Functor.
在調用他們的時候,必須使用各自的函數名:identity_i, indentity_s, indentity_d; 例如
[cpp]
BOOST_TEST(identity_s("abc") == "abc");
BOOST_TEST(identity_i(123) == 123);
BOOST_TEST(identity_d(1.23) == 1.23);
BOOST_TEST(identity_s("abc") == "abc");
BOOST_TEST(identity_i(123) == 123);
BOOST_TEST(identity_d(1.23) == 1.23);
但是,使用OverlaodedFunction,就可以使用統一的名字identity來調用了:
[cpp]
boost::overloaded_function<
const std::string& (const std::string&)
, int (int)
, double (double)
> identity(identity_s, identity_i, identity_d);
// All calls via single `identity` function.
BOOST_TEST(identity("abc") == "abc");
BOOST_TEST(identity(123) == 123);
BOOST_TEST(identity(1.23) == 1.23);
boost::overloaded_function<
const std::string& (const std::string&)
, int (int)
, double (double)
> identity(identity_s, identity_i, identity_d);
// All calls via single `identity` function.
BOOST_TEST(identity("abc") == "abc");
BOOST_TEST(identity(123) == 123);
BOOST_TEST(identity(1.23) == 1.23);