驭风万里无垠

用Boost.Python + CMake + wxPython构建跨语言GUI程序<二>

  • Function

接下来是函数部分,在根目录下边新添加一个子项目,连同其子目录,并且在根目录的CMakeLists.txt里边加入对应声明:

mkdir Function;
touch Function/CMakeLists.txt;
touch Function/test.cpp
对应的根目录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})
接下来就是实际的练习代码,添于test.cpp里。

1> 最常见的自由函数,最基本的C函数:

//dummy function
void dummyFunc()
{
    cout << "Dummy function called!" << endl;
}
对应的Wrapper为:
BOOST_PYTHON_MODULE(function)
{
def(fun, dummyFunc)
..................
..................
}

这里需要留意的是,对应的MODULE里边的那个名字必须和CMakeLists.txt里边制定的库名字完全一样,否则python导入对应的模块时候会报错误。

编译之,只需要:

cd ../Build;
make
ls lib/function.so
cd lib
在Python里边测试,可以用了:
$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> 接下来是函数调用里边,参数和返回值生存期的问题,因为有可能函数返回了一个内部对象,必须要外部来释放,或者返回对象指向参数对象的子对象,或者参数之间存在相互依赖等,这些都必须显示指明,否则就可能被可恶的指针问题说羁绊。

下边是一个很极端的例子:

////////////////////////////////////////////////////////////////////////////////
//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;
} 

想正确的把最后这个Func导入到Python里边用,就必须指明其参数之间的依赖关系以及返回值应用里边的曲曲折折,就是z指向的对象必须又x来管理,而返回值则是x的一个子对象,这里用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> >()     
    );
这种繁琐的情况,还是尽量少用来做公有接口的好吧。
一个测试的例子:
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>
>>> 
这里使用了类成员变量的导出来构造其他的辅助参数对象,例子也很直观。后边在Class的例子里边还有更详尽的阐释。
3> 函数重载
重载是个很好的工具,可以用同样的名字来描述不同的实现,下边的是一个成员函数重载的例子(其实和Free funciton的唯一差别就是声明导出的时候,
要在class_<T>对象的那个.后边加def,而一般函数只要直接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;
    };
};

 

声明的时候,则要费时一点:

 //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)
        ;

上边用了几个辅助函数来指向同一个函数,然后将他们都导出到同一个python对象的同一个成员函数下边即可。

Python里边调用的例子:

>>> 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给出的提示已经包含了几个重载的参数,其中第一个参数就是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

上边是两种不同的参数调用X的重载成员函数版本。

4> 函数参数的默认值

这个是c++允许函数重载的另一种方式,简单的方法是用一个简单的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);}

导出的方式和上边类似:

    //default args
    def("f", fn);
    def("f", fn1);
    def("f", fn2);

当然boost.python提供了一个宏来完成上边的封装,因此用下边的方式则更简单:

BOOST_PYTHON_FUNCTION_OVERLOADS(fn_overloads, fn, 1, 3);

    def("fn", fn, fn_overloads());
上边的宏第一个参数指定了重载函数的名字,第二个是原来的函数名,最后两个参数这表示最少和最多能够接受多少个可变参数。

调用示例:

>>> 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> 类的成员函数参数的默认值

有些时候我们需要和类的成员函数打交道,所以对应的也有一个宏来完成那些繁杂的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);

宏的作用和上边的那个用于普通函数的差不多。

这里边有一个构造函数默认值的问题,参考下边的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 阅读(627) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


<2009年7月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

导航

统计

常用链接

留言簿(3)

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜