BooPython暴露默认参数的C++(非纯)虚方法

2024-10-03 02:46:57 发布

您现在位置:Python中文网/ 问答频道 /正文

在boostpython中,给定一些类X,公开虚拟方法的推荐方法是如下所示包装它。在

我试图将它与指定虚拟方法上的默认参数的功能结合起来。这在Boost文档中也得到了支持。在

然而,没有给出公开也有默认参数的虚拟方法的例子。在

我假设包装器类也必须将参数定义为默认值,并将其传递给底层getItem()。在

默认参数是一个空指针,尽管我没有理由怀疑这是相关的。在

struct X_wrap : X, wrapper<X>                                                                                                                                                                                                                  
{                                                                                                                                                                                                                                                                   
    X_wrap(): X() {}                                                                                                                                                                                                                                  

    // getItem() is a non-Pure Virtual Function in Class X
    // It has a single argument a, which has a default value of 1                                                                                                                                                                                                           
    A* getItem(Z* a=NULL)                                                                                                                                                                                                                                              
    {                                                                                                                                                                                                                                                               
        if (override getItem = this->get_override("getItem"))                                                                                                                                                                                                       
            return getItem(a);                                                                                                                                                                                                                                       
        return X::getItem(a);                                                                                                                                                                                                                                 
    }                                                                                                                                                                                                                                                               
    A* default_getItem(Z* a=NULL) { return this->X::getItem(a); }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
};

然后将其定义为:

^{pr2}$

问题是,默认参数不会作为方法签名的一部分携带。在

Boost提供了一种解决方法:

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(getItem_member_overloads, getItem, 0, 1)

在非虚拟案例中,如何将此应用于def很清楚:

.def("getItem",                                                                                                                                                                                                                                      
     &X::getItem,                                                                                                                                                                                                                              
     getItem_member_overloads());

这将编译并按预期工作。在

然而,当我们有一个虚函数时,包装器和默认函数会使问题复杂化,因此不清楚如何将它们结合起来。我假设上面的方法不是正确的,因为我已经从定义中删除了default_getItem()。在

这让我尝试创建第二组重载:

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(default_getItem_overloads, default_getItem, 0, 1);

宏可以编译,但似乎没有一种方法可以对.def()应用两个独立的重载集,这样就不会导致编译失败。在

Google建议我可以使用boost::python::arg()并将其定义为arg("a")=1

编译如下:

.def("getItem",                                                                                                                                                                                                                                      
     &X::getItem,
     arg("a")=0,                                                                                                                                                                                                                     
     &X_wrap::default_getItem,
     arg("a")=0);

但我得到一个运行时错误:

Boost.Python.ArgumentError: Python argument types in                                                                                                                                                                                                                
    X.getItem(ChildClassOfX)                                                                                                                                                                                                                          
did not match C++ signature:                                                                                                                                                                                                                                        
    getItem(X_wrap {lvalue}, Z* a=0)                                                                                                                                                                                                   
    getItem(X {lvalue}, Z* a=0)

这表明ChildClassOfX由于某种原因与基类X中的getItem()的签名不匹配。在

在这一点上,我有点拐弯抹角-我的定义可能是明显和简单的错误!在

到目前为止,我的任何解决方案要么以某种方式破坏了运行时多态性,要么无法编译。在

任何建议或例子都将是一个巨大的帮助!在

(注意,对于虚函数,缺少对默认函数的要求意味着只有一个函数被传递到.def()中,因此修改非虚平凡的示例看起来很简单-这不是非纯虚拟的情况)

编辑

在网上找到了一个关于其他人问同样问题的参考-这个解决方案与我使用args的尝试很接近,但似乎不起作用,而且与当前的Boost文档不符?它将def()中的包装类用于getItem()和{},并传入一组参数-下面是引用中给出的示例。唯一的另一个区别是默认值是一个值而不是像我这样的指针:

def("override", WrapperClass::func, WrapperClass::default_func, (arg("x"), arg("y")=0, arg("z")=false))

修改我的示例build OK,但是抛出:

Boost.Python.ArgumentError: Python argument types in                                                                                                                                                                                                                
    X.getItem(ChildClassOfX)                                                                                                                                                                                                                          
did not match C++ signature:                                                                                                                                                                                                                                        
    getItem(X_wrap {lvalue}, Z* a=0)                                                                                                                                                                                                   
    getItem(X_wrap {lvalue}, Z* a=0)                                                                                                                                                                                                   

参考文献: http://boost.2283326.n4.nabble.com/Boost-Python-inheritance-optional-parameters-td4592869.html


Tags: 方法函数indefault参数return定义def
1条回答
网友
1楼 · 发布于 2024-10-03 02:46:57

我已经拼凑出一个似乎有效的解决方案,并且遵守多态性的规则。在

秘诀是根本不使用boost::python::argsBOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS宏(尽管我承认它不支持python中的键值参数)。在

只需创建一个辅助函数,该函数的l值与包含虚函数的类相匹配,即X-并且没有其他参数传递给它。这消除了Python与方法签名不匹配的问题,因为参数a及其默认值根本不存在:

A* getItem_noargs_wrap(X& x)
{
    return x.getItem();
}

这似乎毫无意义,但决不是。^ {CD5}}调用是C++到C++,所以默认参数与空签名正确匹配。在

{{cdy>我们现在可以在Python函数中给出一个匹配的函数。在

唯一剩下的就是给编译器一些帮助,让他们知道哪个签名与哪个底层调用匹配:

^{pr2}$

因此,getItem()被Python公开了两次,一次没有参数,使用我们的辅助函数在幕后调用正确的实例方法,一次使用Z*并对非纯虚拟函数使用标准模式。在

第二个调用实际上是匹配:

.def<const char* (X::*)(Z*)>("getItem",

这似乎很有效,但我还没有详尽地测试过,它并没有以某种方式巧妙地打破多态性。在

相关问题 更多 >