Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

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

like image 491
Bernhard Bodenstorfer Avatar asked Aug 23 '11 07:08

Bernhard Bodenstorfer


People also ask

How do you fix ambiguous call of overloading?

There are two ways to resolve this ambiguity: Typecast char to float. Remove either one of the ambiguity generating functions float or double and add overloaded function with an int type parameter.

Why will an ambiguity error arise if a default value is given to an argument of an overloaded function?

If the compiler can not choose a function amongst two or more overloaded functions, the situation is -” Ambiguity in Function Overloading”. The reason behind the ambiguity in above code is that the floating literals 3.5 and 5.6 are actually treated as double by the compiler.

What is ambiguous function C++?

Access to a base class member is ambiguous if you use a name or qualified name that does not refer to a unique function or object. The declaration of a member with an ambiguous name in a derived class is not an error. The ambiguity is only flagged as an error if you use the ambiguous member name.


1 Answers

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.

like image 87
wilx Avatar answered Sep 27 '22 15:09

wilx