boost-python - 使用默认参数公开C ++(非纯)虚方法

问题描述 投票:0回答:1

在boost-python中,给定一些类X,暴露虚拟方法的推荐方法是将其包装起来,如下所示。

我试图将其与在该虚拟方法上指定默认参数的功能结合使用。 Boost文档也支持这一点。

但是,没有给出暴露也具有默认参数的虚拟方法的示例。

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

默认参数是一个NULL指针,虽然我没有理由怀疑(但)这是相关的。

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

然后将其定义为:

.def("getItem",                                                                                                                                                                                                                                      
     &X::getItem,                                                                                                                                                                                                                              
     &X_wrap::default_getItem);

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

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由于某种原因与基类getItem()中的X的签名不匹配。

在这一点上,我有点wing - 我的定义可能是简单而简单的错误!

到目前为止,我所遇到的任何解决方案都以某种方式破坏了运行时多态性,或者没有编译。

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

(对于纯虚函数的注意事项,缺少对默认函数的要求意味着只有一个函数被传递到.def(),所以它看起来很容易修改非虚拟的例子 - 非纯虚拟的情况不是这样)

编辑

在网上找到一个单独的参考文件给其他人提出同样的问题 - 解决方案接近我使用args的尝试,但似乎不起作用并违背当前的Boost文档?它使用def()中的包装类用于getItem()default_getItem(),其中传递了一组args - 下面是参考中给出的示例。唯一的另一个区别是默认值是一个值而不是我的情况下的指针:

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

修改我的示例构建确定,但抛出:

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

python c++ boost boost-python
1个回答
0
投票

我拼凑了一个似乎有效的解决方案,并遵守多态的规则。

秘诀就是根本不使用boost::python::argsBOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS宏(虽然我接受它不会支持python中的键值args)。

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

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

这似乎毫无意义,但它绝不是。 x.getItem()调用是C ++到C ++,因此默认参数与空签名正确匹配。

然而,当我们编写def()时,我们现在可以为Python提供一个真正不带参数的函数,允许它匹配Python中的getItem()调用。

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

.def("getItem",                                                                                                                                                                                                                                      
     &getItem_noargs_wrap);
.def("getItem",                                                                                                                                                                                                                                      
     &X::getItem,                                                                                                                                                                                                                   
     &X_wrap::default_getItem);

所以getItem()被暴露两次到Python - 一次没有参数使用我们的辅助函数在幕后调用正确的实例方法,并且一次使用Z*并使用标准模式用于非纯虚函数。

第二个调用是有效匹配:

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

这似乎运作良好 - 但我没有详尽地测试它不会以某种方式彻底打破多态性。

© www.soinside.com 2019 - 2024. All rights reserved.