由于超类(传递值)导致重载构造函数的模糊调用

时间:2011-08-23 07:39:12

标签: c++ overload-resolution

我在GSL的某些部分写了一个小的C ++包装器并遇到了以下谜题(对我来说)。代码(简称其基本内容)如下:

    #include <stdlib.h>
    struct gsl_vector_view {};

    class Vector : protected gsl_vector_view {
            public:
            Vector ( const Vector& original );
            Vector ( const gsl_vector_view view );
    };

    class AutoVector : public Vector {
            public:
            explicit AutoVector ( const size_t dims );
    };

    void useVector ( const Vector b ) {}

    void test () {
            const AutoVector ov( 2 );
            useVector( ov );
    }

不会使用gcc 4.4.5编译         g ++ -c v.cpp 但是产量

     In function ‘void test()’:
    19: error: call of overloaded ‘Vector(const AutoVector&)’ is ambiguous
    7: note: candidates are: Vector::Vector(gsl_vector_view)
    6: note:                 Vector::Vector(const Vector&)
    19: error:   initializing argument 1 of ‘void useVector(Vector)’

我很惊讶通过调用useVector(Vector)来考虑受保护的基类gsl_vector_view。我原以为useVector属于“The C ++ Programming Language”,第3页,第3页中的“普通大众”。 405因此无法访问受保护的信息,因此不能被它混淆。 我知道我可以通过将构造函数声明为

来摆脱歧义
    explicit Vector ( const gsl_vector_view view );

我不知道(并且,老实说,也不理解),当我将构造函数声明为

时,重载调用的模糊性消失了
    Vector ( const gsl_vector_view& view );

即。通过引用传递参数(无论如何我会考虑正确的做事方式)。

2 个答案:

答案 0 :(得分:4)

重载解析在访问检查之前完成,这就是考虑受保护的基类成员的原因。

过载分辨率在标准的第13.3章中描述。我的解释是,将const AutoVector ov绑定到Vector ( const Vector& original );用户定义的转换派生到基础转换([13.3.3.1.4 / 1])亲切的。对于Vector ( const gsl_vector_view view );,转换序列也是用户定义的转换,因为它是左值到右值的转换,后跟用户定义的转换。因此,两个转换序列被认为是相等的,没有一个比另一个更好,因此你得到了歧义。

现在,如果您将ctor更改为Vector ( const gsl_vector_view& view );,则两次转化都是左值转换,然后是用户定义的转换(派生到基础转换)。这两个可以被订购([13.3.3.2/4])并且转换为const Vector&被认为是更好的,因此没有歧义。

答案 1 :(得分:1)

问题与protected继承或构造函数无关。正常的函数调用也会持续存在这个问题(无论继承什么)。

当您在所有重载版本中通过引用传递时,则选择最近的基类(如果有多于1个基类,它们最接近它的形式不正确)。

如果通过值传递,则所有功能都被认为是同样好的候选者。因此,您收到此编译错误。标准引用了一小段引文,与你的问题有些匹配。

  

§13.3.1(5)
  ...对于没有声明的非静态成员函数   ref-qualifier,附加规则适用: - 即使隐含   object参数不是const限定的,rvalue可以绑定到   参数只要在所有其他方面都可以参数   转换为隐式对象参数的类型。