后面的返回类型语法样式是否应该成为新的 C + + 11程序的默认样式?

C + + 11支持一种新的函数语法:

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

目前,这一功能的声明如下:

int func_name(int x, int y);

新的风格似乎还没有被广泛采用(比如在 gcc stl 中)

然而,在新的 C + + 11程序中,这种新的风格是应该到处都是首选的,还是只有在需要的时候才会使用?

就个人而言,如果可能的话,我更喜欢旧的风格,但是混合风格的代码库看起来非常丑陋。

35879 次浏览

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).

See this nice article: http://www.cprogramming.com/c++11/c++11-auto-decltype-return-value-after-function.html Very good example when to use this syntax without decltype in 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 brilliant explanation also stolen from Alex Allain's article "Because the return value goes at the end of the function, instead of before it, you don't need to add the class scope."

Compare to this possible case when one by accident forget about class scope, and, for bigger disaster, another PersonType is defined in global scope:

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

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.

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

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

with

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

However, one can argue 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);