examples c++ c++11 templates auto

examples - Usar la palabra clave auto C++ 11 para declarar dos(o más) variables



lambda examples c++ (3)

Como mencioné en mi comentario a su respuesta , estoy de acuerdo con el análisis que ha presentado.
La forma más simple del problema ( demo ):

template<class T> void foo (T t) { auto i = t, j = 1; // error: inconsistent deduction for ‘auto’: ‘auto’ and then ‘int’ } int main () {}

En el caso de las plantillas, el compilador en su primera etapa, comprueba la sintaxis básica sin crear instancias. En nuestro caso, nunca invocamos foo() todos modos.

Ahora, en el ejemplo anterior, el decltype(auto) para i sigue siendo auto , porque el tipo dependiente T no se conoce. Sin embargo, j es seguramente int . Por lo tanto, el error del compilador tiene sentido . El comportamiento actual (G ++> = 6), puede o no ser un error. Depende de lo que esperemos del compilador. :-)

Sin embargo, este error no puede ser condenado. Aquí está la cita estándar de apoyo del borrador de C ++ 17 :

7.1.7.4.1 Deducción de tipo de marcador de posición

4 Si el marcador de posición es el especificador automático de tipo, el tipo deducido T que reemplaza a T se determina utilizando las reglas para la deducción de argumentos de plantilla . Obtenga P de T reemplazando las apariciones de auto con un nuevo parámetro de plantilla de tipo inventado U

Lo mismo está presente en el estándar C ++ 14 como 7.1.6.4 / 7.

¿Por qué se informa este error en la primera comprobación de plantilla?

Podemos argumentar con razón que, por qué el compilador está siendo tan "pedante" en la primera comprobación de sintaxis. Ya que, no estamos creando una instancia, ¡entonces no debería estar bien! Incluso si creamos una instancia, ¿no debería dar error solo para las llamadas problemáticas?
Eso es lo que hace g ++ - 5. ¿Por qué se molestaron en cambiarlo?

Creo que es un argumento válido. Con g ++ - 5, si llamo:

foo(1); // ok foo(1.0); // error reported inside `foo()`, referencing this line

Luego, el compilador informa correctamente el error y su jerarquía cuando i y j son de diferentes tipos.

Tengo un código como este:

template<class ListItem> static void printList(QList<ListItem>* list) { for (auto i = list->size() - 1, j = -1; i >= 0; --i) { std::cout << i << ", " << j << ": " << list->at(i) << std::endl; } }

Cuando lo compilo con g ++ 6.2.1 obtengo el siguiente resultado del compilador:

test.cpp: In function ‘void printList(QList<T>*)’: test.cpp:10:7: error: inconsistent deduction for ‘auto’: ‘auto’ and then ‘int’ for (auto i = list->size() - 1, j = -1; i >= 0; --i) { ^~~~

Entendería esto, si las variables tuvieran diferentes tipos como auto i = 0.0, j = 0; , pero en este caso, la lista es un puntero a QList y su método size () devuelve int , -1 en sí mismo también debería ser int . El mensaje de error es un poco extraño también.

Las variables i y j solo son necesarias en este bucle y me gustaría declararlas como parámetros de bucle. No es difícil escribir int lugar de auto, pero me gustaría saberlo: se supone que auto no debe usarse para declarar múltiples variables de una sola vez, o me falta algo aquí y realmente es un código erróneo, o tal vez es el error del compilador?

PS Parece que el uso de una función de plantilla es la parte crítica aquí, ya que el factor fuera del bucle de la plantilla no produce errores. Entonces, más como un error en el compilador?

Demostración en vivo - código mínimo


Este es un error en GCC.

Según [dcl.spec.auto] / 1:

Los especi fi decltype(auto) auto y decltype(auto) tipo se utilizan para designar un tipo de marcador de posición que se reemplazará más tarde por deducción de un inicializador. [...]

Las reglas para la deducción de argumentos de plantilla nunca deducen que un tipo sea auto . El propósito de la deducción en este caso es reemplazar el auto con un tipo deducido.

En el ejemplo, la list tiene un tipo dependiente (depende del parámetro de plantilla ListItem ), por lo que la expresión list->size() - 1 también tiene un tipo dependiente, lo que hace que el tipo de i también sea dependiente, lo que significa que solo Se resolverá en la instanciación de la plantilla de función printList . Sólo entonces se pueden verificar las otras restricciones semánticas relacionadas con esa declaración.

Según [temp.res] / 8:

Saber qué nombres son nombres de tipo permite verificar la sintaxis de cada plantilla. El programa está mal formado, no se requiere diagnóstico, si:

[... larga lista de casos de los cuales ninguno se aplica aquí ...]

De lo contrario, no se emitirá ningún diagnóstico para una plantilla para la que se pueda generar una especialización válida . [ Nota: Si se crea una instancia de una plantilla, los errores se diagnosticarán de acuerdo con las otras reglas de esta Norma. Exactamente cuando se diagnostican estos errores es un problema de calidad de implementación. - nota final ]

(énfasis mío)

GCC se equivoca al emitir ese error al analizar la definición de la plantilla printList , ya que se pueden generar especializaciones claramente válidas de la plantilla. De hecho, si QList no tiene ninguna especialización para la cual size() devuelva algo más que int , la declaración para i y j será válida en todas las instancias de printList .

Todas las citas son de N4606 , el borrador de trabajo (casi) actual, pero las partes relevantes de las citas anteriores no han cambiado desde C ++ 14.

Actualización: Confirmado como una regresión en GCC 6 / 7. Gracias a T.C. por el informe de error.

Actualización: El error original ( 78693 ) se corrigió para las próximas versiones 6.4 y 7.0. También descubrió algunos otros problemas con la forma en que GCC maneja tales construcciones, lo que resulta en otros dos informes de errores: 79009 y 79013 .


Voy a resumir la información recibida sobre el tema entonces.

El problema en el código de ejemplo está en usar una función de plantilla. El compilador realiza primero una comprobación genérica de una plantilla sin crear instancias, esto significa que los tipos, que son argumentos de plantilla (y los tipos que dependen de ellos, como otras plantillas) no se conocen, y el auto si depende de esos tipos desconocidos se deduce a auto nuevo (o no deducido en algún tipo concreto). Nunca me pareció que incluso después de la deducción auto todavía puede ser auto . Ahora el texto de error del compilador original tiene mucho sentido: la variable j se deduce de tipo int , pero la variable i sigue siendo auto después de la deducción. Dado que auto e int son tipos diferentes, el compilador genera el error.