Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should the trailing return type syntax style become the default for new C++11 programs? [closed]

C++11 supports a new function syntax:

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

Currently this function would be declared as:

int func_name(int x, int y); 

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

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

Personally, I prefer the old style when possible, but a code-base with mixed styles looks pretty ugly.

like image 318
mirk Avatar asked Jun 26 '12 20:06

mirk


People also ask

Why use trailing return type?

The trailing return type feature removes a C++ limitation where the return type of a function template cannot be generalized if the return type depends on the types of the function arguments.

Can return type be auto?

In C++14, you can just use auto as a return type.

What does Decltype auto do?

1 The auto and decltype(auto) type-specifiers designate a placeholder type that will be replaced later, either by deduction from an initializer or by explicit specification with a trailing-return-type. The auto type-specifier is also used to signify that a lambda is a generic lambda.


2 Answers

There are certain cases where you must use a trailing return type. Most notably, a lambda return type, if specified, must be specified via a trailing return type. Also, if your return type utilizes a decltype that requires that the argument names are in scope, a trailing return type must be used (however, one can usually use declval<T> to work around this latter issue).

The trailing return type does have some other minor advantages. For example, consider a non-inline member function definition 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 typedefs are not in scope until after the name of the class appears before ::get_integers, so we have to repeat the class qualification twice. If we use a trailing return type, we don't need to repeat the name of the type:

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

In this example, it's not such a big deal, but if you have long class names or member functions of class templates that are not defined inline, then it can make a big difference in readability.

In his "Fresh Paint" session at C++Now 2012, Alisdair Meredith pointed out that if you use trailing return types consistently, the names of all of your functions line up neatly:

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

I've used trailing return types everywhere in CxxReflect, so if you're looking for an example of how code looks using them consistently, you can take a look there (e.g, the type class).

like image 65
James McNellis Avatar answered Sep 17 '22 21:09

James McNellis


In addition to what others said, the trailing return type also allows to use this, which is not otherwise allowed

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 declaration, we used the traditional style. However since this is not allowed at that position, the compiler does not implicitly use it. So the a.end() uses the statically declared type of a to determine what end overload of vector<int> it is going to call, which ends up being the non-const version.

like image 38
Johannes Schaub - litb Avatar answered Sep 19 '22 21:09

Johannes Schaub - litb