2011-08-23 9 views
5

Escribí un pequeño contenedor de C++ alrededor de algunas partes de GSL y encontré el siguiente acertijo (para mí). El código (reducida a sus elementos esenciales) es como sigue:Llamada ambigua del constructor sobrecargado debido a la superclase (paso por valor)

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

no se compilará usando gcc 4.4.5 g ++ -c v.cpp pero dió

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

me sorprende que la protected clase base gsl_vector_view es tomada en consideración por la llamada de useVector (Vector). Hubiera pensado que useVector pertenece al "público general" en el lenguaje de "The C++ Programming Language", 3rd e., P. 405 y por lo tanto no tiene acceso a esa información protegida y, por lo tanto, no puede ser confundida por ella. Sé que puede deshacerse de la ambigüedad al declarar el constructor como

explicit Vector (const gsl_vector_view view); 

Lo que yo no sabía (y, sinceramente, no entiendo tampoco), es que la ambigüedad de la llamada sobrecarga desaparece cuando declarar el constructor como

Vector (const gsl_vector_view& view); 

es decir, pasar el argumento de referencia (que yo consideraría todos modos la forma correcta de hacer las cosas).

+0

+1, No tiene nada que ver con la herencia 'protected'; así que reformatear la pregunta. – iammilind

+0

por cierto. la ambigüedad desaparece cuando declaras useVector para tomar una referencia también – PlasmaHH

Respuesta

4

La resolución de sobrecarga se realiza antes de la verificación de acceso, por eso incluso se consideran los miembros de la clase base protegida.

La resolución de sobrecarga se describe en el capítulo 13.3 de la norma. Mi interpretación es que el enlace const AutoVector ov a Vector (const Vector& original); es conversión definida por el usuario, Conversión a base ([13.3.3.1.4/1]) tipo. Para Vector (const gsl_vector_view view);, la secuencia de conversión también es una conversión definida por el usuario porque es conversión lvalue a rvalue seguida de la conversión definida por el usuario. Entonces, ambas secuencias de conversión se consideran iguales, ninguna es mejor que la otra, y así obtienes la ambigüedad.

Ahora, si cambia el ctor a Vector (const gsl_vector_view& view);, tanto la conversión son conversión-lvalue-a-valor seguido de conversión definida por el usuario (de conversión derivados-a-base). Esos dos pueden ordenarse ([13.3.3.2/4]) y la conversión a const Vector& se considera mejor y, por lo tanto, no hay ambigüedad.

1

La pregunta no tiene que ver con protected herencia o constructor como tal. Este problema persistirá con la llamada a función normal también (con cualquier herencia).

Cuando pasa por referencia en todas las versiones de sobrecarga, se elige la clase base más cercana (si hay más de 1 clase base que están más cerca entonces está mal formado).

En caso de paso por valor, todas las funciones se consideran candidatas igualmente válidas. Por lo tanto, está obteniendo este error de compilación. Hay un pequeño pasaje de la cita de estándar, que coincide un poco con su pregunta.

§ 13.3.1 (5)
...Para funciones miembro no estáticas declaradas sin un calificador ref , se aplica una regla adicional: - incluso si el parámetro de objeto implícito no está const-qualified, un valor r puede vincularse al parámetro siempre que en todos los demás aspectos El argumento puede ser convertido al tipo del parámetro de objeto implícito.

Cuestiones relacionadas