valores tipos salida retornan referencias referencia que por paso parametros parametro funciones entrada con c++ reference c++11 initializer-list uniform-initialization

c++ - tipos - ¿Por qué no puedo inicializar una referencia en una lista de inicializadores con inicialización uniforme?



referencias en c++ (3)

(Nota: estoy escribiendo esta respuesta con el beneficio de 2 años de retrospectiva desde la pregunta original, y para poner parte de la información de los comentarios en una respuesta real para que se pueda buscar).

Por supuesto, se supone que la inicialización de una referencia de tipo S& con una referencia de tipo S& se vincula directamente.

El problema es un defecto en el estándar C ++ 11 y fue solucionado por DR1288 . El texto corregido aparece en C ++ 14.

El Comité ha aclarado que el texto corregido es lo que estaba destinado a C ++ 11, por lo que un "compilador conforme" debería implementar la versión corregida.

g ++ 4.8 siguió el texto publicado del estándar C ++ 11; sin embargo, una vez que este problema salió a la luz, g ++ 4.9 implementó la versión corregida, incluso con el -std=c++11 .

Tenga en cuenta que el problema tampoco se limita a las listas de inicialización del constructor, por ejemplo: S s; S &t{s}; S s; S &t{s}; no funciona en g ++ 4.8, ni tampoco S s; S &t = s; S &u { t }; S s; S &t = s; S &u { t };

Es decir, ¿por qué hace esto?

struct S {}; struct T { T(S& s) : s{s} {} S& s; }; int main() { S s; T t{s}; }

Dame un error de compilación con GCC 4.7:

test.cpp: In constructor ''T::T(S&)'': test.cpp:5:18: error: invalid initialization of non-const reference of type ''S&'' from an rvalue of type ''<brace-enclosed initializer list>''

?

Para corregir el error, tengo que cambiar los s{s} a s(s) . ¿No rompe esto, erm, la uniformidad de la inicialización uniforme?

EDIT : lo intenté con clang, y clang lo acepta, así que tal vez es un error de GCC?


Creo que es un error en el compilador. Los dos párrafos que tratan la inicialización de referencia a través de la inicialización de lista son (en n3337):

§8.5.4 / 3

La inicialización de lista de un objeto o referencia de tipo T se define de la siguiente manera:

  • De lo contrario, si la lista de inicializadores tiene un solo elemento de tipo E y T no es un tipo de referencia o su tipo de referencia está relacionado con E, el objeto o la referencia se inicializa desde ese elemento; Si se requiere una conversión de reducción (ver más abajo) para convertir el elemento a T, el programa no está bien formado.

  • De lo contrario, si T es un tipo de referencia, un prvalue temporal del tipo referenciado por T se inicializa en la lista, y la referencia está vinculada a ese temporal. [Nota: Como es habitual, la vinculación fallará y el programa no se formará correctamente si el tipo de referencia es una referencia de valor a un tipo no constante. - nota final]

El compilador parece estar aplicando el último párrafo, cuando debería estar aplicando el primero, ya que la referencia se define como

8.5.3 / 4

Dados los tipos "cv1 T1" y "cv2 T2", "cv1 T1" está relacionado con la referencia a "cv2 T2" si T1 es el mismo tipo que T2, o T1 es una clase base de T2.

En el caso de la pregunta, los tipos de referencia y el inicializador dentro de la lista de inicialización de llaves son exactamente iguales, lo que significa que la inicialización debe ser válida.

En el borrador del FDIS, los párrafos equivalentes tenían el orden invertido. La implicación es que el borrador del FDIS (n3290) no permitió la inicialización de la lista de llaves de * lvalue * s. Por otro lado, al leer el texto parece obvio que se trata de un error en el estándar y que la intención era tener el orden de n3337:

  • De lo contrario, si T es un tipo de referencia, un prvalue temporal del tipo referenciado por T se inicializa en la lista, y la referencia está vinculada a ese temporal.

  • De lo contrario, si la lista de inicializadores tiene un solo elemento, el objeto o la referencia se inicializa desde ese elemento; Si se requiere una conversión de reducción (ver más abajo) para convertir el elemento a T, el programa no está bien formado.

El orden en ese documento significa que debido a que todos los tipos de referencia son manejados por la primera cláusula, mencionar la referencia en el siguiente párrafo no tendría sentido.


Sí, es un bug . Esto es algo nuevo y se votó en el documento de trabajo en febrero de 2012 ( link ).

Nicol Bolas destaca que gcc es en realidad el compilador conforme al estándar C ++ 11 aprobado por FDIS porque los cambios en el documento de trabajo se realizaron después de eso.