尾随返回类型语法样式应该成为新C++ 11程序的默认样式吗?

mir*_*irk 80 c++ auto c++11 trailing-return-type

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

auto func_name(int x, int y) -> int;
Run Code Online (Sandbox Code Playgroud)

目前此函数将声明为:

int func_name(int x, int y);
Run Code Online (Sandbox Code Playgroud)

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

但是,这种新风格是否应该在新的C++ 11程序中随处可见,还是仅在需要时使用?

就个人而言,我更喜欢旧款式,但是混合风格的代码库看起来很丑陋.

Jam*_*lis 94

在某些情况下,您必须使用尾随返回类型.最值得注意的是,必须通过尾随返回类型指定lambda返回类型(如果已指定).此外,如果您的返回类型使用的decltype是要求参数名称在范围内,则必须使用尾随返回类型(但是,通常可以declval<T>用来解决后一个问题).

尾随返回类型确实具有一些其他小优点.例如,考虑使用传统函数语法的非内联成员函数定义:

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
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

在之前出现类的名称之前::get_integers,成员typedef不在范围内,因此我们必须重复两次类限定.如果我们使用尾随返回类型,我们不需要重复该类型的名称:

auto my_awesome_type::get_integers() const -> integer_sequence
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,它并不是什么大问题,但是如果你有长类名或类模板的成员函数没有内联定义,那么它可以在可读性方面产生很大的不同.

在C++ Now 2012的"Fresh Paint"会议中,Alisdair Meredith指出,如果你始终使用尾随返回类型,那么所有函数的名称都排列整齐:

auto foo() -> int;
auto bar() -> really_long_typedef_name;
Run Code Online (Sandbox Code Playgroud)

我到处使用后返回类型在CxxReflect,所以如果你正在寻找的代码看起来如何使用它们一贯的例子,你可以看看那里(例如,type).

  • `#define fn auto` 你可以编写像 Rust 一样的代码;-) (4认同)

Joh*_*itb 61

除了其他人所说的,尾随返回类型也允许使用this,否则不允许使用

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(); }
};
Run Code Online (Sandbox Code Playgroud)

在第二个宣言中,我们使用了传统风格.但是,由于this在该位置不允许,编译器不会隐式使用它.因此,a.end()使用静态声明的类型a来确定它将调用哪个end重载vector<int>,最终成为非const版本.

  • 尽管这是一个很好的概念说明(使用返回类型中的成员),但很有趣,因为在C ++ 14中,在没有转换的内联定义中指定类型是完全多余的;我们现在可以使用完全返回类型推导。:P (2认同)

s3r*_*vac 19

另一个优点是当函数返回指向函数的指针时,尾随返回类型语法可以更具可读性.例如,比较

void (*get_func_on(int i))(int);
Run Code Online (Sandbox Code Playgroud)

auto get_func_on(int i) -> void (*)(int);
Run Code Online (Sandbox Code Playgroud)

但是,人们可以说只需通过为函数指针引入类型别名就可以实现更好的可读性:

using FuncPtr = void (*)(int);
FuncPtr get_func_on(int i);
Run Code Online (Sandbox Code Playgroud)

  • 我个人总是更喜欢使用 Func = void(int); Func* get();` 保持指针性质明显 - 如果有的话,因为不会因为*单个*出现而破坏类型库。在后一种情况下,尾随 RT 会派上用场! (3认同)

Pio*_*ycz 9

看到这篇好文章:http://www.cprogramming.com/c++11/c++11-auto-decltype-return-value-after-function.html 非常好的例子何时在游戏中使用没有decltype的语法:

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;
}
Run Code Online (Sandbox Code Playgroud)

从Alex Allain的文章中也可以看出精彩的解释"因为返回值在函数结束时发生,而不是在它之前,你不需要添加类范围."

比较这种可能的情况,当偶然忘记类范围,并且,对于更大的灾难,另一个PersonType在全局范围中定义:

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

  • 我不确定这属于"灾难"类别:如果类型错误,代码将无法编译.运行时错误可能带来灾难性的后果; 编译时错误,而不是那么多. (6认同)
  • @JamesMcNellis比较编译器输出:`prog.cpp:13:12:错误:'PersonType Person :: getPersonType()'的原型与类'Person'中的任何一个都不匹配``prog.cpp:13:1:错误:'PersonType'没有命名类型`编译器的第一个错误,至少对我来说,更难以理解. (4认同)