C ++ 11 prend en charge une nouvelle syntaxe de fonction:
auto func_name(int x, int y) -> int;
Actuellement, cette fonction serait déclarée comme:
int func_name(int x, int y);
Le nouveau style ne semble pas encore largement adopté (disons dans le gcc stl)
Cependant, ce nouveau style devrait-il être préféré partout dans les nouveaux programmes C ++ 11, ou ne sera-t-il utilisé qu'en cas de besoin?
Personnellement, je préfère l'ancien style lorsque c'est possible, mais une base de code avec des styles mixtes semble assez moche.
c++
c++11
auto
trailing-return-type
obscur
la source
la source
decltype
les arguments.Réponses:
Il existe certains cas où vous devez utiliser un type de retour de fin. Plus particulièrement, un type de retour lambda, s'il est spécifié, doit être spécifié via un type de retour de fin. En outre, si votre type de retour utilise un
decltype
qui nécessite que les noms d'argument soient dans la portée, un type de retour de fin doit être utilisé (cependant, on peut généralement l'utiliserdeclval<T>
pour contourner ce dernier problème).Le type de retour de fin présente d'autres avantages mineurs. Par exemple, considérons une définition de fonction membre non en ligne utilisant la syntaxe de fonction traditionnelle:
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 { // ... }
Les typedefs de membres ne sont dans la portée qu'après l'apparition du nom de la classe
::get_integers
, nous devons donc répéter la qualification de classe deux fois. Si nous utilisons un type de retour de fin, nous n'avons pas besoin de répéter le nom du type:auto my_awesome_type::get_integers() const -> integer_sequence { // ... }
Dans cet exemple, ce n'est pas si grave, mais si vous avez des noms de classe longs ou des fonctions membres de modèles de classe qui ne sont pas définis en ligne, cela peut faire une grande différence en termes de lisibilité.
Dans sa session "Fresh Paint" à C ++ Now 2012, Alisdair Meredith a souligné que si vous utilisez les types de retour de fin de manière cohérente, les noms de toutes vos fonctions s'alignent parfaitement:
auto foo() -> int; auto bar() -> really_long_typedef_name;
J'ai utilisé des types de retour de fin partout dans CxxReflect , donc si vous cherchez un exemple de l'apparence du code en les utilisant de manière cohérente, vous pouvez y jeter un œil (par exemple, la
type
classe ).la source
En plus de ce que d'autres ont dit, le type de retour de fin permet également d'utiliser
this
, ce qui n'est pas autorisé autrementstruct 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(); } };
Dans la deuxième déclaration, nous avons utilisé le style traditionnel. Cependant, puisque ce
this
n'est pas autorisé à cette position, le compilateur ne l'utilise pas implicitement. Donc, lea.end()
utilise le type déclaré statiquement dea
pour déterminer quelleend
surchargevector<int>
va appeler, ce qui finit par être la version non const.la source
Un autre avantage est que la syntaxe de type retour de fin peut être plus lisible lorsque la fonction renvoie un pointeur vers une fonction. Par exemple, comparez
void (*get_func_on(int i))(int);
avec
auto get_func_on(int i) -> void (*)(int);
Cependant, on peut affirmer qu'une meilleure lisibilité peut être obtenue simplement en introduisant un alias de type pour le pointeur de fonction:
using FuncPtr = void (*)(int); FuncPtr get_func_on(int i);
la source
Voir cet article sympa: http://www.cprogramming.com/c++11/c++11-auto-decltype-return-value-after-function.html Très bon exemple quand utiliser cette syntaxe sans decltype dans le jeu :
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; }
Et une explication brillante également volée à l'article d'Alex Allain "Parce que la valeur de retour va à la fin de la fonction, au lieu d'être avant, vous n'avez pas besoin d'ajouter la portée de la classe."
Comparez à ce cas possible quand on oublie accidentellement la portée de la classe et, pour un désastre plus important, un autre PersonType est défini dans la portée globale:
typedef float PersonType; // just for even more trouble /*missing: Person::*/ PersonType Person::getPersonType () { return _person_type; }
la source
prog.cpp:13:12: error: prototype for 'PersonType Person::getPersonType()' does not match any in class 'Person'
vs.prog.cpp:13:1: error: 'PersonType' does not name a type
La première erreur du compilateur est, du moins pour moi, pire à comprendre.