c++ c++11 gcc clang overload-resolution

c++ - Diferencia de resolución de sobrecarga entre gcc y clang que involucra al constructor de movimientos y al constructor ''Derived(Base &&)''



c++11 overload-resolution (1)

Creo que Clang tiene razón aquí. GCC no debe aceptar el código.

La razón es la forma en que se especifica la resolución de sobrecarga para los constructores de la copia del objeto que se produce en una declaración de return en [class.copy] p32 (énfasis mío):

Cuando se cumplen los criterios para la elección de un constructor de copia / movimiento, [...] y el objeto a copiar se designa mediante un lvalue, [...] se realiza la resolución de sobrecarga para seleccionar el constructor para la copia. como si el objeto fuera designado por un rvalor. Si la primera resolución de sobrecarga falla o no se realizó, o si el tipo del primer parámetro del constructor seleccionado no es una referencia de valor al tipo del objeto (posiblemente calificada como CV) , la resolución de sobrecarga se realiza nuevamente, considerando el objeto como un lvalue

En este ejemplo, se cumplen los criterios para la elección (por la primera viñeta en [class.copy] p31 ) y el objeto a copiar se designa con un lvalue, por lo que se aplica este párrafo.

La resolución de sobrecarga se intenta primero como si el objeto fuera designado por un valor de r. Los constructores explicit no son candidatos (ver a continuación una explicación de por qué), por lo que se selecciona el constructor Derived(Base&&) . Sin embargo, esto se incluye en "el tipo del primer parámetro del constructor seleccionado no es una referencia de valor al tipo de objeto" (en su lugar, es una referencia de valor al tipo de clase base del objeto), por lo que la resolución de sobrecarga debe realizarse de nuevo , considerando el objeto como un valor.

Esta segunda resolución de sobrecarga falla, porque el único constructor viable (de nuevo, los constructores explicit no son candidatos) tiene un parámetro de referencia rvalue, que no puede vincularse al valor l. Clang muestra el error de error de resolución de sobrecarga resultante.

Para completar la explicación, he aquí por qué los constructores explicit no son candidatos para ninguna resolución de sobrecarga (todo el énfasis es mío).

Primero, [dcl.init] p15 dice que:

La inicialización que se produce en la forma = de una inicialización o condición de refuerzo o igual (6.4), así como en el paso de argumentos, el retorno de función , el lanzamiento de una excepción (15.1), el manejo de una excepción (15.3) y el miembro agregado La inicialización (8.5.1), se llama inicialización de la copia ".

A continuación, nos fijamos en [over.match.ctor] p1 :

Para la inicialización de la copia , las funciones candidatas son todos los constructores de conversión (12.3.1) de esa clase.

Finalmente, vemos que los constructores explicit no están convirtiendo constructores en [class.conv.ctor] p1 :

Un constructor declarado sin el especificador de función explicit especifica una conversión de los tipos de sus parámetros al tipo de su clase. Tal constructor se llama un constructor de conversión .

GCC (probado con 4.9) acepta el siguiente testcase:

struct Base {}; struct Derived : Base { Derived(); explicit Derived(const Derived&); explicit Derived(Derived&&); explicit Derived(const Base&); Derived(Base&&); }; Derived foo() { Derived result; return result; } int main() { Derived result = foo(); }

Clang (probado con 3.5) lo rechaza con el siguiente mensaje de error:

test.cpp:13:10: error: no matching constructor for initialization of ''Derived'' return result; ^~~~~~ test.cpp:8:5: note: candidate constructor not viable: no known conversion from ''Derived'' to ''Base &&'' for 1st argument Derived(Base&&); ^ test.cpp:4:5: note: candidate constructor not viable: requires 0 arguments, but 1 was provided Derived(); ^

Quien tiene razon