Le type de syntaxe du type de retour de fin doit-il être utilisé par défaut pour les nouveaux programmes C ++ 11?

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 être largement adopté (par exemple, dans le fichier 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 cela est possible, mais une base de code avec des styles mixtes est plutôt moche.

Il existe certains cas où vous devez utiliser un type de retour de fin. Plus particulièrement, un type de retour lambda, si spécifié, doit être spécifié via un type de retour final. De plus, si votre type de retour utilise un decltype qui requirejs que les noms d’argument soient dans la scope, un type de retour de fin doit être utilisé (cependant, on peut généralement utiliser declval pour contourner ce dernier problème).

Le type de retour de fin de page présente d’autres avantages mineurs. Par exemple, considérons une définition de fonction membre non inline utilisant la syntaxe de fonction traditionnelle:

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

Les types de membres ne sont pas dans la scope tant que le nom de la classe n’apparaît pas avant ::get_integers , nous devons donc répéter la qualification de la classe deux fois. Si nous utilisons un type de retour, 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 très grave, mais si vous avez des noms de classes longues 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” de C ++ Now 2012, Alisdair Meredith a souligné que si vous utilisez systématiquement les types de retour, les noms de toutes les fonctions s’alignent parfaitement:

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

J’ai utilisé des types de retour de suivi partout dans CxxReflect , donc si vous cherchez un exemple de la façon dont le code les utilise de manière cohérente, vous pouvez y jeter un coup d’œil (par exemple, la classe de type ).

En plus de ce que les autres ont dit, le type de retour arrière permet également d’utiliser this , this qui n’est pas autorisé autrement.

 struct A { std::vector 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. Toutefois, comme this n’est pas autorisé à cette position, le compilateur ne l’utilise pas implicitement. Donc, le a.end() utilise le type statiquement déclaré de a pour déterminer la surcharge end du vector qu’il va appeler, ce qui finit par être la version non-const.

Un autre avantage est que la syntaxe trailing-return-type peut être plus lisible lorsque la fonction renvoie un pointeur sur une fonction. Par exemple, comparez

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

avec

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

Cependant, on peut avancer 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); 

Voir cet article sympathique: http://www.cprogramming.com/c++11/c++11-auto-decltype-return-value-after-function.html Très bon exemple d’utilisation de cette syntaxe sans décltype 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 géniale également volée à l’article d’Alex Allain “Parce que la valeur de retour va à la fin de la fonction, au lieu de l’avoir avant, vous n’avez pas besoin d’append la scope de la classe.”

Comparez-le à un cas possible où, accidentellement, vous oubliez l’étendue de la classe et, dans le cas d’une catastrophe majeure, un autre PersonType est défini dans la scope globale:

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