primero, asegúrese de que entiende de lo que está hablando.C++ copia de inicialización e inicialización directa, el caso extraño
voy a resumir la regla aquí en primer lugar (leer norma N3225 8,5/16, 13.3.1.3, 13.3.1.4, 13.3.1.5 y),
1) Para la inicialización directa, todos los constructores se considerarán el conjunto de sobrecarga, la resolución de sobrecarga seleccionará la mejor de acuerdo con las reglas de resolución de sobrecarga.
2) Para la inicialización de copia y el tipo de fuente es igual al tipo de destino o derivado del tipo de destino, la regla es igual a la anterior excepto que solo los constructores convertidores (constructores sin explícito) se considerarán como el conjunto de sobrecarga. En realidad, esto significa que los constructores de copia/movimiento explícitos no se considerarán en el conjunto de sobrecarga.
3) Para los casos de inicialización de copia no incluidas en (2) anterior (tipo de fuente es diferente de tipo de destino y no derivadas de tipo de destino), consideramos en primer lugar secuencias de conversión definidas por el usuario que pueden convertir desde el tipo de fuente a la tipo de destino o (cuando se usa una función de conversión) a una clase derivada del mismo. Si la conversión se realiza correctamente, el resultado se utiliza para inicializar directamente el objeto de destino.
3.1) Durante esta secuencia de conversión definida por el usuario, se considerarán tanto las funciones de conversión (funciones no explícitas) como las funciones de conversión no explícitas, de acuerdo con las reglas 8.5/16 y 13.3.1.4.
3.2) El resultado prvalue inicializará directamente el objeto de destino, como las reglas enumeradas en (1), consulte 8.5/16.
Bien, suficiente para las reglas, veamos un código extraño, que realmente no tengo idea de dónde está mi razonamiento equivocado, o simplemente todos los compiladores están equivocados. Por favor, ayúdame, gracias.
struct A
{
A (int) { }
A() { }
explicit A(const A&) { }
};
struct B
{
operator A() { return 2; }
//1) visual c++ and clang passes this
//gcc 4.4.3 denies this, says no viable constructor available
};
int main()
{
B b;
A a = b;
//2) oops, all compilers deny this
}
En mi comprensión, para (1),
operator A() { return 2; }
Debido C++ tiene una regla que función de retorno se toma como copia-inicialización, de acuerdo con la regla anterior, 2 serán en primer lugar convierte implícitamente a A, lo cual debería estar bien porque A tiene un constructor A (int). Entonces, el prvalue temporal convertido se usará para inicializar directamente el objeto devuelto, lo que también debería ser correcto, ya que la inicialización directa puede hacer uso del constructor de copia explícito. Entonces GCC está equivocado.
Para (2),
A a = b;
En mi comprensión, en primer lugar b se convierte implícitamente a A, por el operador A(), y luego el valor convertido se utilizará para directo inicializar A, que puede por supuesto, llame al constructor de copia explícita? Por lo tanto, esto debería pasar compilación y todos los compiladores están equivocados?
Tenga en cuenta que para (2), tanto C++ visuales como clang tienen un error similar a "Error, no se puede convertir de B a A", pero si elimino la palabra clave explícita en el constructor de copia de A, el error se ha ido ..
Gracias por leer.
editar 1
Porque alguien todavía no consiguió lo que quería decir, cito el siguiente estándar de 8,5/16,
De lo contrario (es decir, para el contra copias restantes casos de inicialización), secuencias de conversión definidas por el usuario que pueden convertir del tipo de fuente a el tipo de destino o (cuando se usa una función de conversión ) a clase derivada del mismo se enumeran como se describe en 13.3.1.4, y el mejor se elige a través de la resolución de sobrecarga (13.3). Si la conversión no se puede hacer o es ambigua, la inicialización está mal formada. La función seleccionada se llama con la expresión de inicializador como su argumento ; si la función es un constructor , la llamada inicializa un temporal de la versión cv-no calificada del tipo de destino. El temporal es un valor prvero. El resultado de la llamada (que es el temporal para el caso constructor) luego se utiliza para directo initialize, de acuerdo con los reglas anteriores, el objeto que es el destino de la copia -inicialización . En ciertos casos, se permite una implementación a eliminar la copia inherente a esta inicialización directa al construir el resultado intermedio directamente en el objeto que se inicializa; ver 12.2, 12.8.
Tenga en cuenta que mencionó la inicialización directa después de la conversión definida por el usuario. Lo que significa, en mi entender, que el siguiente código obedecerá a las reglas como lo que comenté, lo que se confirma con ambos clang, coomeau en línea, C++ visual, pero GCC 4.4.3 falla tanto (1) como (2). Aunque esta es una regla extraña, pero sigue el razonamiento del estándar.
struct A
{
A (int) { }
A() { }
explicit A(const A&) { }
};
int main()
{
A a = 2; //1)OK, first convert, then direct-initialize
A a = (A)2; //2)oops, constructor explicit, not viable here!
}
Comeau Online acepta el fragmento de código completo tal como está escrito. –
bien, gracias. Esto me da cierta confianza de que mi razonamiento al menos no va en la dirección equivocada.^_^ – user534498
@James McNellis: Sin embargo, Comeau Online rechaza el código en mi respuesta, aunque según el razonamiento de OP se supone que debe ser aceptado. – AnT