Should the return type type syntax style become standard for new C ++ 11 programs?

C ++ 11 supports the new function syntax:

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

Currently, this function will be declared as:

 int func_name(int x, int y); 

The new style does not seem to have been widely adopted yet (say in gcc stl)

However, should this new style be preferred everywhere in the new C ++ 11 programs, or will it be used only when necessary?

Personally, I prefer the old style when possible, but the codebase with mixed styles looks pretty ugly.

+70
c ++ c ++ 11 trailing-return-type auto
Jun 26 '12 at 20:11
source share
4 answers

In some cases, you must use the final return type. In particular, the lambda return type, if specified, must be specified through the final return type. In addition, if the return type uses the decltype type decltype which requires the argument names to be in scope, you must use the final return type (however, you can usually use declval<T> to get around this last problem).

The final return type has other minor advantages. For example, consider defining a non-inline member function using the traditional function syntax:

 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 { // ... } 

Member type definitions are not in scope until the class name appears before ::get_integers , so we must repeat the class qualification twice. If we use a finite return type, we do not need to repeat the type name:

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

This is not such a big problem in this example, but if you have long class names or member functions of class templates that are not defined by built-in, then this can go a long way in readability.

In his "Fresh Paint" session in C ++ Now 2012, Alisdair Meredith noted that if you use consecutive finite return types, the names of all your functions are aligned neatly:

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

I used finite return types everywhere in CxxReflect , so if you are looking for an example of how the code looks consistent using them, you can take a look there (for example, the type class ).

+84
Jun 26 '12 at 20:28
source share

In addition to what others have said, the return type of return also allows the use of this , which is otherwise not permitted.

 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(); } }; 

In the second ad we used a traditional style. However, since this not allowed in this position, the compiler does not use it implicitly. Thus, a.end() uses the statically declared type a to determine which end overload vector<int> will cause, which ends with a non-constant version.

+55
Jun 27. 2018-12-12T00:
source share

Another advantage is that the syntax of type trailing-return-type can be more readable when the function returns a pointer to the function. For example, compare

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

from

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

However, it can be argued that better readability can be achieved simply by introducing a type alias for the function pointer:

 using FuncPtr = void (*)(int); FuncPtr get_func_on(int i); 
+14
Jan 12 '17 at 15:05
source share

See this nice article: http://www.cprogramming.com/c++11/c++11-auto-decltype-return-value-after-function.html A very good example is when to use this syntax without a description in the game :

 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; } 

And a brilliant explanation, also stolen from the article by Alex Allen, "Because the return value comes at the end of the function, and not before it, you do not need to add the scope of the class."

Compare with this possible case when one of them forgets about the class, and for a bigger disaster, the other type of PersonType is defined in the global scope:

 typedef float PersonType; // just for even more trouble /*missing: Person::*/ PersonType Person::getPersonType () { return _person_type; } 
+7
Jun 26 2018-12-12T00:
source share



All Articles