una todas tipos programacion parametros llamar lenguaje las funciones funcion estructura ejemplos con como c++ c++11 auto trailing-return-type

todas - ¿Debería el estilo de sintaxis del tipo de retorno final convertirse en el predeterminado para los nuevos programas de C++ 11?



tipos de funciones en programacion (4)

C ++ 11 admite una nueva sintaxis de función:

auto func_name(int x, int y) -> int;

Actualmente esta función se declararía como:

int func_name(int x, int y);

El nuevo estilo no parece ser ampliamente adoptado aún (por ejemplo, en el gcc stl)

Sin embargo, ¿debería preferirse este nuevo estilo en todos los nuevos programas de C ++ 11, o solo se usará cuando sea necesario?

Personalmente, prefiero el estilo antiguo cuando es posible, pero una base de código con estilos mixtos parece bastante fea.


Además de lo que otros dijeron, el tipo de devolución final también permite usar this , que de otro modo no está permitido

struct A { std::vector<int> a; // OK, works as expected auto begin() const -> decltype(a.begin()) { return a.begin(); } // FAIL, does not work: "decltype(a.end())" will be "iterator", but // the return statement returns "const_iterator" decltype(a.end()) end() const { return a.end(); } };

En la segunda declaración, usamos el estilo tradicional. Sin embargo, como this no está permitido en esa posición, el compilador no lo usa implícitamente. Entonces, a.end() usa el tipo declarado a.end() de a para determinar qué sobrecarga end de vector<int> va a llamar, que termina siendo la versión no constante.


Hay ciertos casos en los que debe usar un tipo de devolución final. En particular, un tipo de retorno lambda, si se especifica, se debe especificar a través de un tipo de retorno final. Además, si el tipo de devolución utiliza un tipo de decltype que requiere que los nombres de los argumentos estén dentro del alcance, se debe usar un tipo de devolución final (sin embargo, normalmente se puede usar declval<T> para declval<T> este problema).

El tipo de devolución final tiene algunas otras ventajas menores. Por ejemplo, considere una definición de función miembro no en línea usando la sintaxis de la función tradicional:

struct my_awesome_type { typedef std::vector<int> integer_sequence; integer_sequence get_integers() const; }; my_awesome_type::integer_sequence my_awesome_type::get_integers() const { // ... }

Los typedefs de los miembros no están en el alcance hasta que el nombre de la clase aparezca antes de ::get_integers , por lo que debemos repetir la calificación de la clase dos veces. Si utilizamos un tipo de devolución final, no necesitamos repetir el nombre del tipo:

auto my_awesome_type::get_integers() const -> integer_sequence { // ... }

En este ejemplo, no es tan importante, pero si tiene nombres largos de clase o funciones miembro de plantillas de clase que no están definidas en línea, entonces puede marcar una gran diferencia en la legibilidad.

En su sesión de "Pintura fresca" en C ++ Now 2012, Alisdair Meredith señaló que si utiliza los tipos de devolución final consistentemente, los nombres de todas sus funciones se alinean perfectamente:

auto foo() -> int; auto bar() -> really_long_typedef_name;

He utilizado los tipos de retorno final en todas partes en CxxReflect , por lo que si está buscando un ejemplo de cómo el código parece usarlos consistentemente, puede echar un vistazo allí (por ejemplo, la clase de type ).


Otra ventaja es que la sintaxis del tipo de retorno final puede ser más legible cuando la función devuelve un puntero a una función. Por ejemplo, comparar

void (*get_func_on(int i))(int);

con

auto get_func_on(int i) -> void (*)(int);

Sin embargo, se puede argumentar que se puede lograr una mejor legibilidad simplemente introduciendo un alias de tipo para el puntero de función:

using FuncPtr = void (*)(int); FuncPtr get_func_on(int i);


Vea este bonito artículo: http://www.cprogramming.com/c++11/c++11-auto-decltype-return-value-after-function.html Muy buen ejemplo de cuándo usar esta sintaxis sin decltype en el juego :

class Person { public: enum PersonType { ADULT, CHILD, SENIOR }; void setPersonType (PersonType person_type); PersonType getPersonType (); private: PersonType _person_type; }; auto Person::getPersonType () -> PersonType { return _person_type; }

Y una explicación brillante también fue robada del artículo de Alex Allain "Debido a que el valor de retorno va al final de la función, en lugar de antes, no es necesario agregar el alcance de la clase".

Compárese con este posible caso cuando uno por accidente se olvida del alcance de la clase y, para un desastre mayor, otro PersonType se define en el alcance global:

typedef float PersonType; // just for even more trouble /*missing: Person::*/ PersonType Person::getPersonType () { return _person_type; }