Con el lanzamiento de GCC 4.8.0, tenemos un compilador que admite la deducción automática del tipo de devolución, parte de C ++ 14. Con -std=c++1y
, puedo hacer esto:
auto foo() { //deduced to be int
return 5;
}
Mi pregunta es: ¿Cuándo debo usar esta función? ¿Cuándo es necesario y cuándo hace que el código sea más limpio?
escenario 1
El primer escenario en el que puedo pensar es siempre que sea posible. Todas las funciones que se pueden escribir de esta manera deberían serlo. El problema con esto es que no siempre puede hacer que el código sea más legible.
Escenario 2
El siguiente escenario es evitar tipos de retorno más complejos. Como un ejemplo muy ligero:
template<typename T, typename U>
auto add(T t, U u) { //almost deduced as decltype(t + u): decltype(auto) would
return t + u;
}
No creo que eso realmente sea un problema, aunque supongo que tener el tipo de retorno depende explícitamente de los parámetros podría ser más claro en algunos casos.
Escenario 3
A continuación, para evitar la redundancia:
auto foo() {
std::vector<std::map<std::pair<int, double>, int>> ret;
//fill ret in with stuff
return ret;
}
En C ++ 11, a veces podemos simplemente return {5, 6, 7};
reemplazar un vector, pero eso no siempre funciona y necesitamos especificar el tipo en el encabezado y el cuerpo de la función. Esto es puramente redundante, y la deducción automática del tipo de devolución nos salva de esa redundancia.
Escenario 4
Finalmente, se puede usar en lugar de funciones muy simples:
auto position() {
return pos_;
}
auto area() {
return length_ * width_;
}
Sin embargo, a veces, podemos mirar la función, queriendo saber el tipo exacto, y si no se proporciona allí, tenemos que ir a otro punto en el código, como donde pos_
se declara.
Conclusión
Con esos escenarios establecidos, ¿cuál de ellos demuestra ser una situación en la que esta característica es útil para hacer que el código sea más limpio? ¿Qué pasa con los escenarios que he olvidado mencionar aquí? ¿Qué precauciones debo tomar antes de usar esta función para que no me muerda más tarde? ¿Hay algo nuevo que esta característica trae a la mesa que no sea posible sin ella?
Tenga en cuenta que las múltiples preguntas están destinadas a ayudar a encontrar perspectivas desde las cuales responder esto.
fuente
->decltype(t+u)
con deducción automática mata a SFINAE.Respuestas:
C ++ 11 plantea preguntas similares: cuándo usar la deducción de tipo de retorno en lambdas y cuándo usar
auto
variables.La respuesta tradicional a la pregunta en C y C ++ 03 ha sido "a través de los límites de las declaraciones, hacemos explícitos los tipos, dentro de las expresiones generalmente están implícitas, pero podemos hacerlas explícitas con conversiones". C ++ 11 y C ++ 1y presentan herramientas de deducción de tipos para que pueda omitir el tipo en nuevos lugares.
Lo sentimos, pero no vas a resolver esto por adelantado haciendo reglas generales. Debe mirar un código en particular y decidir por sí mismo si ayuda o no a la legibilidad para especificar tipos en todo el lugar: ¿es mejor que su código diga "el tipo de esta cosa es X", o es mejor para su código para decir, "el tipo de esta cosa es irrelevante para comprender esta parte del código: el compilador necesita saber y probablemente podríamos resolverlo, pero no necesitamos decirlo aquí".
Dado que la "legibilidad" no está definida objetivamente [*], y además varía según el lector, usted tiene la responsabilidad como autor / editor de un código que no puede ser totalmente satisfecho por una guía de estilo. Incluso en la medida en que una guía de estilo especifique normas, diferentes personas preferirán normas diferentes y tenderán a encontrar algo desconocido para que sea "menos legible". Por lo tanto, la legibilidad de una regla de estilo propuesta en particular a menudo solo se puede juzgar en el contexto de las otras reglas de estilo vigentes.
Todos sus escenarios (incluso el primero) encontrarán uso para el estilo de codificación de alguien. Personalmente, considero que el segundo es el caso de uso más convincente, pero aun así preveo que dependerá de sus herramientas de documentación. No es muy útil ver documentado que el tipo de retorno de una plantilla de función es
auto
, mientras que verlo documentadodecltype(t+u)
crea una interfaz publicada en la que puede (con suerte) confiar.[*] Ocasionalmente, alguien intenta hacer algunas mediciones objetivas. En la pequeña medida en que alguien obtiene resultados estadísticamente significativos y aplicables en general, los programadores que trabajan trabajan los ignoran por completo, a favor de los instintos del autor de lo que es "legible".
fuente
1.0 + 27U
estamos afirmando lo último, cuando escribimos(double)1.0 + (double)27U
estamos afirmando lo primero. La simplicidad de la función, el grado de duplicación y la evitacióndecltype
podrían contribuir a eso, pero ninguno será decisivo de manera confiable.auto
en general.auto
palabra clave, se mostrará el tipo de retorno real.int*
, pero lo que es realmente significativo, si es que lo hace, es que la razónint*
es porque eso es lo questd::vector<int>::iterator_type
está con sus opciones de compilación actuales.En términos generales, el tipo de retorno de función es de gran ayuda para documentar una función. El usuario sabrá lo que se espera. Sin embargo, hay un caso en el que creo que sería bueno eliminar ese tipo de retorno para evitar la redundancia. Aquí hay un ejemplo:
Este ejemplo está tomado del documento oficial del comité N3493 . El propósito de la función
apply
es reenviar los elementos de astd::tuple
a una función y devolver el resultado. Losint_seq
ymake_int_seq
son solo parte de la implementación, y probablemente solo confundirán a cualquier usuario que intente entender lo que hace.Como puede ver, el tipo de retorno no es más que una
decltype
de las expresiones devueltas. Además, alapply_
no estar destinado a ser visto por los usuarios, no estoy seguro de la utilidad de documentar su tipo de retorno cuando es más o menos igual alapply
de uno. Creo que, en este caso particular, soltar el tipo de retorno hace que la función sea más legible. Tenga en cuenta que este mismo tipo de devolución se ha eliminado y reemplazadodecltype(auto)
en la propuesta para agregarapply
al estándar, N3915 (también tenga en cuenta que mi respuesta original es anterior a este documento):Sin embargo, la mayoría de las veces, es mejor mantener ese tipo de retorno. En el caso particular que describí anteriormente, el tipo de retorno es bastante ilegible y un usuario potencial no obtendrá nada al saberlo. Una buena documentación con ejemplos será mucho más útil.
Otra cosa que aún no se ha mencionado: si bien
declype(t+u)
permite usar la expresión SFINAE ,decltype(auto)
no lo hace (aunque hay una propuesta para cambiar este comportamiento). Tomemos, por ejemplo, unafoobar
función que llamará a lafoo
función miembro de un tipo si existe o llame a labar
función miembro del tipo si existe, y suponga que una clase siempre tiene exactamentefoo
obar
ambas cosas a la vez:Llamar
foobar
a una instancia deX
se mostraráfoo
mientras se llamafoobar
a una instancia deY
se mostrarábar
. Si utiliza la deducción automática de tipo de retorno en su lugar (con o sindecltype(auto)
), no obtendrá la expresión SFINAE ni invocaráfoobar
una instancia de ninguno de ellosX
oY
activará un error en tiempo de compilación.fuente
Nunca es necesario En cuanto a cuándo debería, obtendrá muchas respuestas diferentes al respecto. Yo diría que no hasta que sea una parte aceptada del estándar y bien respaldada por la mayoría de los principales compiladores de la misma manera.
Más allá de eso, va a ser un argumento religioso. Personalmente, diría que nunca poner el tipo de retorno real aclara el código, es mucho más fácil para el mantenimiento (puedo ver la firma de una función y saber lo que devuelve en lugar de tener que leer el código), y elimina la posibilidad de que cree que debería devolver un tipo y el compilador piensa que otro está causando problemas (como ha sucedido con cada lenguaje de script que he usado). Creo que el auto fue un gran error y causará mucho más dolor que ayuda. Otros dirán que debe usarlo todo el tiempo, ya que se ajusta a su filosofía de programación. En cualquier caso, esto está fuera del alcance de este sitio.
fuente
#define
s para convertir C ++ en VB. Las características generalmente tienen un buen consenso dentro de la mentalidad del lenguaje sobre qué es el uso apropiado y qué no, de acuerdo a lo que los programadores de ese lenguaje están acostumbrados. La misma característica puede estar presente en varios idiomas, pero cada uno tiene sus propias pautas sobre su uso.auto
es pura bendición. Elimina mucha redundancia. Es simplemente un dolor repetir el tipo de retorno a veces. Si desea devolver una lambda, puede ser incluso imposible sin almacenar el resultado en astd::function
, lo que puede generar algunos gastos generales.auto
para que siempre coincida con el tipo de retorno de la función pasada.auto
para el tipo de retorno final.]No tiene nada que ver con la simplicidad de la función (como supone un duplicado ahora eliminado de esta pregunta).
El tipo de retorno es fijo (no se usa
auto
) o depende de manera compleja de un parámetro de plantilla (se usaauto
en la mayoría de los casos, emparejadodecltype
cuando hay múltiples puntos de retorno).fuente
Considere un entorno de producción real: muchas funciones y pruebas unitarias, todas interdependientes en el tipo de retorno de
foo()
. Ahora suponga que el tipo de retorno necesita cambiar por cualquier razón.Si el tipo de retorno está en
auto
todas partes, y las personas que llamanfoo()
y las funciones relacionadas se usanauto
al obtener el valor devuelto, los cambios que deben realizarse son mínimos. Si no, esto podría significar horas de trabajo extremadamente tedioso y propenso a errores.Como ejemplo del mundo real, me pidieron que cambiara un módulo del uso de punteros sin formato en todas partes a punteros inteligentes. Arreglar las pruebas unitarias fue más doloroso que el código real.
Si bien hay otras formas de manejar esto, el uso de
auto
tipos de retorno parece ser una buena opción.fuente
decltype(foo())
?typedef
las declaraciones sy alias (es decir, lausing
declaración de tipo) son mejores en estos casos, especialmente cuando tienen un alcance de clase.Quiero proporcionar un ejemplo donde el tipo de retorno automático es perfecto:
Imagine que desea crear un alias corto para una llamada de función posterior larga. Con auto, no necesita cuidar el tipo de devolución original (tal vez cambie en el futuro) y el usuario puede hacer clic en la función original para obtener el tipo de devolución real:
PD: Depende de esta pregunta.
fuente
Para el escenario 3, cambiaría el tipo de retorno de la firma de la función con la variable local que se devolverá. Sería más claro para los programadores del cliente que la función retorna. Me gusta esto:
Escenario 3 Para evitar la redundancia:
Sí, no tiene una palabra clave automática, pero el principal es el mismo para evitar la redundancia y brindar a los programadores que no tienen acceso a la fuente un momento más fácil.
fuente
vector<map<pair<int,double>,int>
y luego usarlo.