c++ - "Ambiguous resolution"选择性构造函数继承错误

标签 c++ inheritance c++11 constructor overloading

我正在尝试整理一些代码。

我有 16 个类,它们都有一些共同的功能,我用宏抽象了这些功能:

#define COMMON4( CLASS, BASE, ASSIGN, CHECK ) \
    explicit CLASS( PyObject* pyob, bool owned=false ) \
        : BASE{ pyob, owned } { \
        validate(); } \
        \
    CLASS& operator=( const Object& rhs  ) { \
        return *this = rhs.ptr(); } \
    \ 
    CLASS& operator=( PyObject* rhsp ) { \
        if(ptr()!=rhsp) set(ASSIGN);  return *this; }  \
        \
    bool accepts( PyObject* pyob ) const override { \
        return pyob && CHECK; }

#define COMMON5( CLASS, BASE, CHECK ) \
    COMMON4( CLASS, BASE, rhsp, CHECK ) \
    CLASS( const Object& ob ) : BASE{ ob.ptr() } { \
        validate(); } \

    // Class Type
    class Type: public Object
    {
    public:
        COMMON5( Type, Object, _Type_Check(pyob) )

        Type( const Type& t ) : Object{t}  { validate(); }
    };

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

    class Boolean: public Object
    {
    public:
        COMMON5( Boolean, Object, PyObject_IsTrue(pyob) != -1 )

        Boolean( const Boolean& ob ) : Object{ob}  { validate(); }

        Boolean( bool v=false )       { set( PyBool_FromLong(v?1:0), true ); validate(); }      // create from bool
        Boolean& operator=( bool v )  { set( PyBool_FromLong(v?1:0), true ); return *this; }

        operator bool()         const { return as_bool(); }
    };

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

    class Long: public Object
    {
    public:
        COMMON4( Long, Object, PyNumber_Long(rhsp), _Long_Check(pyob) )

        // π I *think* the explicit was originally on the wrong function below
        explicit Long( const Long& ob )                     : Object{ ob }                                               { validate(); }
                 Long( const Object& ob )                   : Object{ PyNumber_Long(ob.ptr())                   , true } { validate(); } // ... any object
        :
    }
    : (etc)

不过,我刚刚发现C++11支持构造函数继承,例如:

Code Demo

#include <string>
#include <iostream>

using namespace std;

class B {
     public:
     B() { cout << "B:-\n"; }
     B(int i) { cout << "B:int\n"; }
     B(float i) { cout << "B:float\n"; }
};

class D : public B {
     using B::B;
     public:
     D(double i) : B() { cout << "D:double\n"; }
};

class D2 : public B {
     using B::B;
     public:
     D2(float i) : B() { cout << "D:float\n"; }
};

class D3 : public B {
     using B::B;
     public:
     D3(float i) = delete;
};

int main() {
    D a{5};    // B:int
    D b{5.f};  // B:float
    D c{5.};   // B:- D:double

    D2 d{5.f}; // B:- D:float

    //D3 e{5.f}; // error: use of deleted function 'D3::D3(float)'
}

此代码表明可以回退到基类构造函数,同时提供覆盖它们的机会。

这正是我所需要的,因为偶尔会有类(class)稍微打破模式。

这是重写:

using CheckType = bool(PyObject*);
inline PyObject* setDefault(PyObject* pyob){ return pyob; };

template< typename Derived,  typename Base,  CheckType checkfunc,  decltype(setDefault) setfunc = setDefault >
class ObjBase : public Object
{
public:
    ObjBase(){ };

    explicit ObjBase( PyObject* pyob, bool owned=false ) : Base{pyob,owned} { validate(); }

    Derived& operator=( const Object& rhs  )  {                                      return *this = rhs.ptr(); }
    Derived& operator=( PyObject*     rhsp )  { if(ptr()!=rhsp) set(setfunc(rhsp));  return *this; }

    bool accepts( PyObject* pyob )  const override { return pyob && checkfunc(pyob); }

    ObjBase( const Object& ob ) : Base{ob.ptr()}  { validate(); }
};

// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

// Class Type
class Type: public ObjBase< Type, Object, _Type_Check > {
    using          ObjBase< Type, Object, _Type_Check >::ObjBase;
    using          ObjBase< Type, Object, _Type_Check >::operator=;

public:
    // COMMON5( Type, Object, _Type_Check(pyob) )

    Type( const Type& t ) : ObjBase{t}  { validate(); }
};

// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

inline bool bool_check( PyObject* pyob ){ return PyObject_IsTrue(pyob) != -1; }
class Boolean: public ObjBase< Boolean, Object, bool_check > // <-- 1. Candidate is the implicit copy assignment operator
{
    using ObjBase< Boolean, Object, bool_check >::ObjBase;
    using ObjBase< Boolean, Object, bool_check >::operator=;

public:
    // COMMON5( Boolean, Object, PyObject_IsTrue(pyob) != -1 )

    Boolean( const Boolean& ob ) : ObjBase{ob}  { validate(); }

    Boolean( bool v=false )       { set( PyBool_FromLong(v?1:0), true ); validate(); }      // create from bool

    Boolean& operator=( bool v ) { set( PyBool_FromLong(v?1:0), true ); return *this; } // <-- 2. Candidate function

    operator bool()         const { return as_bool(); }
};
:
: (etc)

第一类作品——类型。但是,当我尝试使用此类时, bool 类会导致编译器错误。

错误:重载运算符“=”的使用不明确(操作数类型为“Py::Boolean”和“Py::Long”)

Boolean b{true}; 
Long l{15};
b = l; // <-- ERROR: Use of overloaded operator '=' is ambiguous (with operand types 'Py::Boolean' and 'Py::Long')

错误指定了我在代码中标记的两个候选人:

    // Candidate function
    Boolean& operator=( bool v ) { set( PyBool_FromLong(v?1:0), true ); return *this; }

但另一个指向类声明本身的行:

// Candidate is the implicit copy assignment operator
class Boolean: public ObjBase< Boolean, Object, bool_check > // <-- ?! 
{ ...

就是这个我不明白。

我的第一个猜测是与基类中的赋值运算符存在一些冲突。

但是,错误具体是说“Candidate is the implicit copy assignment operator”

查找“隐式复制赋值运算符”,http://en.cppreference.com/w/cpp/language/as_operator

...表示生成了一个隐式复制赋值,但如果满足特定条件则将其删除。

我的猜测是原来的类(class)符合这些标准。但是将大多数方法移回基类的行为可能意味着现在没有满足这些标准。

但是,我看不到。

如何插入这一进程?

编辑:完整的源文件列表here

编辑:我还注意到,通过将 operator= 重载移回 ObjBase,'*this' 现在不正确了。将其替换为“static_cast(*this)”会产生额外的错误。

最佳答案

第二个候选者可能是隐式定义的复制赋值运算符,它未在源代码中显示,因此编译器指向类本身。

您的 Long 类可以隐式转换为各种可转换为 bool 的整数类型,这些类型也可以转换为 Boolean,并且这两种类型都可以分配给 Boolean,因此编译器在执行分配之前不知道要转换成哪个。

您可以显式转换,这样编译器就不需要检查:

b = bool(l);

或等效地,但更明确(对于某些读者来说可能更清楚):

b = static_cast<bool>(l);

您可能希望避免在类型之间进行过多的显式转换,这会造成混淆并导致此类问题。要禁用隐式转换并要求显式转换以告诉编译器您要执行哪些转换,请将转换构造函数设置为 explicit,或将转换运算符设置为 explicit(或两者)。

关于c++ - "Ambiguous resolution"选择性构造函数继承错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27093008/

相关文章:

c++ - 未正确推断对全局函数的引用

c++ - 在引用初始化中使用已删除的复制构造函数进行复制初始化

c++ - 如何将 constexpr 值传递给采用 const 引用的 CUDA 设备端函数?

c++ - 是什么阻止了 C++ 成为 C 的严格超集?

c++ - 为什么接受数组的 C++ 模板不比接受 GCC 5.3 和 Clang 4.0 的指针更专业?

c++ - 如何统计程序执行过程中的(CPU cycles)和(instructions retired)总数?

java - 为什么不能从父类中实现的接口(interface)对象调用子类方法

c++ - 如何访问子类中的小部件?

c# - 将 IEnumerable<Derived> 转换为 IEnumerable<BaseClass>

java - 在基 Activity 类中初始化公共(public) View