开发者

Ambiguous call of overloaded constructor due to super class (pass by value)

开发者 https://www.devze.com 2023-03-29 19:59 出处:网络
I wrote a little C++ wrapper around some parts of GSL and encounter the following puzzle (for me). The code (reduced to its essentials) is as follows:

I wrote a little C++ wrapper around some parts of GSL and encounter the following puzzle (for me). The code (reduced to its essentials) is as follows:

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

    class Vector : protected gsl_vector_view {
            public:
            Vector ( const Vector& original );
            Vector ( const gsl_vector_vi开发者_StackOverflowew 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 );
    }

will not compile using gcc 4.4.5 g++ -c v.cpp but yield

     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)’

I am surprised that the protected base class gsl_vector_view is taken into consideration by the call of useVector( Vector ). I would have thought that useVector belongs to "the general public" in the parlance of "The C++ Programming Language", 3rd e., p. 405 and thus does not have access to that protected information and, hence, cannot be confused by it. I know that I can get rid of the ambiguity by declaring the constructor as

    explicit Vector ( const gsl_vector_view view );

What I did not know (and, honestly, do not understand either), is that the ambiguity of the overloaded call disappears when I declare the constructor as

    Vector ( const gsl_vector_view& view );

i.e. pass the argument by reference (which I would anyway consider the proper way of doing things).


Overload resolution is done before access checking, that is why even the protected base class' members are considered.

Overload resolution is described in chapter 13.3 of the standard. My interpretation is that binding const AutoVector ov to Vector ( const Vector& original ); is user defined conversion, a derived-to-base Conversion ([13.3.3.1.4/1]) kind. For Vector ( const gsl_vector_view view );, the conversion sequence is also user defined conversion because it is lvalue-to-rvalue conversion followed by user defined conversion. So, both conversion sequences are considered equal, none is better than the other, and thus you get the ambiguity.

Now, if you change the ctor to Vector ( const gsl_vector_view& view );, both conversion are lvalue-to-value conversion followed by user defined conversion (derived-to-base Conversion). Those two can be ordered ([13.3.3.2/4]) and the conversion to const Vector& is considered better and thus there is no ambiguity.


The question has not to do with protected inheritance or constructor as such. This problem will persist with normal function call also (with whatever inheritance).

When you are passing by reference in all the overload versions, then the nearest base class is chosen (if there are more than 1 base class which are nearest then it's ill formed).

In case of pass by value, all the functions are considered equally well candidates. Thus you are getting this compilation error. There is a small passage of quote from standard, which matches somewhat to your question.

§ 13.3.1 (5)
... For non-static member functions declared without a ref-qualifier, an additional rule applies: — even if the implicit object parameter is not const-qualified, an rvalue can be bound to the parameter as long as in all other respects the argument can be converted to the type of the implicit object parameter.

0

精彩评论

暂无评论...
验证码 换一张
取 消