用Boost.Python + CMake + wxPython構(gòu)建跨語言GUI程序<二>
- Function
接下來是函數(shù)部分,在根目錄下邊新添加一個(gè)子項(xiàng)目,連同其子目錄,并且在根目錄的CMakeLists.txt里邊加入對(duì)應(yīng)聲明:
mkdir Function; touch Function/CMakeLists.txt; touch Function/test.cpp
對(duì)應(yīng)的根目錄CMakeLists.txt后邊加入:
add_subdirectory(Function)
編輯Function的CMakeLists.txt:
project(Function)
set(lib_target function)
include_directories(${Boost_INCLUDE_DIRS})
add_library(${lib_target} SHARED test.cpp)
set_target_properties(${lib_target} PROPERTIES PREFIX "")
target_link_libraries(${lib_target} ${Boost_LIBRARIES})
接下來就是實(shí)際的練習(xí)代碼,添于test.cpp里。
1> 最常見的自由函數(shù),最基本的C函數(shù):
//dummy function void dummyFunc() { cout << "Dummy function called!" << endl; }
對(duì)應(yīng)的Wrapper為:
BOOST_PYTHON_MODULE(function) { def(fun, dummyFunc) .................. .................. }
這里需要留意的是,對(duì)應(yīng)的MODULE里邊的那個(gè)名字必須和CMakeLists.txt里邊制定的庫名字完全一樣,否則python導(dǎo)入對(duì)應(yīng)的模塊時(shí)候會(huì)報(bào)錯(cuò)誤。
編譯之,只需要:
cd ../Build; make ls lib/function.so
cd lib
在Python里邊測(cè)試,可以用了:
$python Python 2.6.2 (r262:71600, Aug 8 2009, 19:23:16) [GCC 4.4.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import function >>> function.dummyFunc() Dummy function called! >>>
2> 接下來是函數(shù)調(diào)用里邊,參數(shù)和返回值生存期的問題,因?yàn)橛锌赡芎瘮?shù)返回了一個(gè)內(nèi)部對(duì)象,必須要外部來釋放,或者返回對(duì)象指向參數(shù)對(duì)象的子對(duì)象,或者參數(shù)之間存在相互依賴等,這些都必須顯示指明,否則就可能被可惡的指針問題說羈絆。
下邊是一個(gè)很極端的例子:
//////////////////////////////////////////////////////////////////////////////// //calling policy struct InnerType { int i; int j; }; struct RefType { float i; double j; }; struct ComposedType { InnerType contained; RefType* ref; }; //really bad ? InnerType& Func(ComposedType& x, RefType* z) { x.ref = z; return x.contained; }
想正確的把最后這個(gè)Func導(dǎo)入到Python里邊用,就必須指明其參數(shù)之間的依賴關(guān)系以及返回值應(yīng)用里邊的曲曲折折,就是z指向的對(duì)象必須又x來管理,而返回值則是x的一個(gè)子對(duì)象,這里用Policy來指定:
class_<ComposedType>("ComposedType") .def_readwrite("contained", &ComposedType::contained) .def_readonly("ref", &ComposedType::ref); class_<RefType>("RefType") .def_readwrite("i", &RefType::i) .def_readwrite("j", &RefType::j); class_<InnerType>("InnerType") .def_readwrite("i", &InnerType::i) .def_readwrite("j", &InnerType::j); def("Func", Func, return_internal_reference<1, with_custodian_and_ward<1, 2> >() );
這種繁瑣的情況,還是盡量少用來做公有接口的好吧。
一個(gè)測(cè)試的例子:
Python 2.6.2 (r262:71600, Aug 8 2009, 19:23:16) [GCC 4.4.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import function >>> x=function.ComposedType() >>> x.contained.i=1 >>> x.contained.j=2 >>> z=function.RefType() >>> z.i=1 >>> z.j=3 >>> y=function.Func(x,z) >>> y.i 1 >>> y.j 2 >>> y <function.InnerType object at 0x7fead87ff910> >>>
這里使用了類成員變量的導(dǎo)出來構(gòu)造其他的輔助參數(shù)對(duì)象,例子也很直觀。后邊在Class的例子里邊還有更詳盡的闡釋。
3> 函數(shù)重載
重載是個(gè)很好的工具,可以用同樣的名字來描述不同的實(shí)現(xiàn),下邊的是一個(gè)成員函數(shù)重載的例子(其實(shí)和Free funciton的唯一差別就是聲明導(dǎo)出的時(shí)候,
要在class_<T>對(duì)象的那個(gè).后邊加def,而一般函數(shù)只要直接Def即可):
//////////////////////////////////////////////////////////////////////////////// //Overloadding struct X { bool f(int a) { return true; } bool f(int a, double b) { return true; } bool f(int a, double b, char c) { return true; } int f(int a, int b, int c) { return a + b + c; }; };
聲明的時(shí)候,則要費(fèi)時(shí)一點(diǎn):
//helpers bool (X::*fx1)(int) = &X::f; bool (X::*fx2)(int, double) = &X::f; bool (X::*fx3)(int, double, char)= &X::f; int (X::*fx4)(int, int, int) = &X::f; class_<X>("X") .def("f", fx1) .def("f", fx2) .def("f", fx3) .def("f", fx4) ;
上邊用了幾個(gè)輔助函數(shù)來指向同一個(gè)函數(shù),然后將他們都導(dǎo)出到同一個(gè)python對(duì)象的同一個(gè)成員函數(shù)下邊即可。
Python里邊調(diào)用的例子:
>>> import function >>> obj=function.X() >>> help(obj.f) Help on method f: f(...) method of function.X instance f( (X)arg1, (int)arg2) -> bool : C++ signature : bool f(X {lvalue},int) f( (X)arg1, (int)arg2, (float)arg3) -> bool : C++ signature : bool f(X {lvalue},int,double) f( (X)arg1, (int)arg2, (float)arg3, (str)arg4) -> bool : C++ signature : bool f(X {lvalue},int,double,char) f( (X)arg1, (int)arg2, (int)arg3, (int)arg4) -> int : C++ signature : int f(X {lvalue},int,int,int)
這里help給出的提示已經(jīng)包含了幾個(gè)重載的參數(shù),其中第一個(gè)參數(shù)就是C++的this指針或者python的self。
>>> obj.f(1,1.1) True >>> obj.f(1,1, 3) 5 >>> function.X.f(obj, 1, 1.2, "msg") True
上邊是兩種不同的參數(shù)調(diào)用X的重載成員函數(shù)版本。
4> 函數(shù)參數(shù)的默認(rèn)值
這個(gè)是c++允許函數(shù)重載的另一種方式,簡(jiǎn)單的方法是用一個(gè)簡(jiǎn)單的wrapper來寫一些helper,如下:
//////////////////////////////////////////////////////////////////////////////// //Default args int fn(int, double = 3.14, char const* = "hello") { return 1; } //wrapper int fn1(int x) {return fn(x);} int fn2(int x, double y) { return fn(x,y);}
導(dǎo)出的方式和上邊類似:
//default args def("f", fn); def("f", fn1); def("f", fn2);
當(dāng)然boost.python提供了一個(gè)宏來完成上邊的封裝,因此用下邊的方式則更簡(jiǎn)單:
BOOST_PYTHON_FUNCTION_OVERLOADS(fn_overloads, fn, 1, 3);
def("fn", fn, fn_overloads());
上邊的宏第一個(gè)參數(shù)指定了重載函數(shù)的名字,第二個(gè)是原來的函數(shù)名,最后兩個(gè)參數(shù)這表示最少和最多能夠接受多少個(gè)可變參數(shù)。
調(diào)用示例:
>>> func = function.f >>> help(func) Help on built-in function f: f(...) f( (int)arg1, (float)arg2, (str)arg3) -> int : C++ signature : int f(int,double,char const*) f( (int)arg1) -> int : C++ signature : int f(int) f( (int)arg1, (float)arg2) -> int : C++ signature : int f(int,double) >>> fn = function.fn >>> help(fn) Help on built-in function fn: fn(...) fn( (int)arg1 [, (float)arg2 [, (str)arg3]]) -> int : C++ signature : int fn(int [,double [,char const*]]) >>> func(1,2.2, "str") 1 >>> fn(1) 1 >>> fn(1, 2.2) 1
5> 類的成員函數(shù)參數(shù)的默認(rèn)值
有些時(shí)候我們需要和類的成員函數(shù)打交道,所以對(duì)應(yīng)的也有一個(gè)宏來完成那些繁雜的wrapper:
//////////////////////////////////////////////////////////////////////////////// //Mem_fun struct Y { Y(int i, int j, int k=0, int p=1.2){} void mem_fn(int i, int j = 0, double k=1.2, const std::string& str="msg"){} }; BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(mem_fn_overloads, mem_fn, 1, 4);
宏的作用和上邊的那個(gè)用于普通函數(shù)的差不多。
這里邊有一個(gè)構(gòu)造函數(shù)默認(rèn)值的問題,參考下邊的optional模板:
//Mem_fn and optional init class_<Y>("Y", init<int, int, optional<int, double> >()) .def("mem_fn", &Y::mem_fn, mem_fn_overloads());
posted on 2009-08-10 20:49 skyscribe 閱讀(631) 評(píng)論(0) 編輯 收藏 引用