C++ 尾随返回类型语法样式是否应该成为新C++;11个节目?

C++ 尾随返回类型语法样式是否应该成为新C++;11个节目?,c++,c++11,auto,trailing-return-type,C++,C++11,Auto,Trailing Return Type,C++11支持新的函数语法: auto func_name(int x, int y) -> int; 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() c

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

auto func_name(int x, int y) -> int;
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
{
    // ...
}
目前,此函数将声明为:

int func_name(int x, int y);
新样式似乎还没有被广泛采用(比如在gcc stl中)

然而,在新的C++11程序中,这种新的样式应该在任何地方都是首选的,还是只在需要时才使用


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

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

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

auto func_name(int x, int y) -> int;
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
{
    // ...
}
在本例中,这没什么大不了的,但是如果您有未内联定义的长类名称或类模板的成员函数,那么它在可读性方面会有很大的不同

Alisdair Meredith在2012年举行的C++Now大会上指出,如果一致使用尾随返回类型,那么所有函数的名称将整齐排列:

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

我在中的所有地方都使用了尾随返回类型,因此,如果您正在寻找代码如何一致地使用它们的示例,您可以在那里查看一下(例如,)。

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

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

auto func_name(int x, int y) -> int;
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
{
    // ...
}
在本例中,这没什么大不了的,但是如果您有未内联定义的长类名称或类模板的成员函数,那么它在可读性方面会有很大的不同

Alisdair Meredith在2012年举行的C++Now大会上指出,如果一致使用尾随返回类型,那么所有函数的名称将整齐排列:

auto foo() -> int;
auto bar() -> really_long_typedef_name;
我在中的所有地方都使用了尾随返回类型,因此,如果您正在寻找代码如何一致地使用它们的示例,您可以在那里查看(例如,)。

请参阅这篇漂亮的文章: 在游戏中不使用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;
}
Alex Allain的文章中也有精彩的解释:“因为返回值在函数的末尾,而不是之前,所以不需要添加类范围。”

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

typedef float PersonType; // just for even more trouble
/*missing: Person::*/
PersonType Person::getPersonType ()
{
    return _person_type;
}
请看这篇精彩的文章: 在游戏中不使用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;
}
Alex Allain的文章中也有精彩的解释:“因为返回值在函数的末尾,而不是之前,所以不需要添加类范围。”

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

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

除了其他人所说的,后面的返回类型还允许使用
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(); }
};
结构A{ std::载体a; //好的,一切正常 auto begin()const->decltype(a.begin()){返回a.begin();} //失败,不起作用:“decltype(a.end())”将是“迭代器”,但 //return语句返回“const_iterator” decltype(a.end())end()常量{返回a.end();} };
在第二次声明中,我们使用了传统风格。但是,由于该位置不允许使用此,编译器不会隐式使用它。因此
a.end()
使用静态声明的
a
类型来确定它要调用的
end
向量
重载是什么,它最终是非常量版本。

除了其他人所说的之外,后面的返回类型还允许使用
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(); }
};
结构A{ std::载体a; //好的,一切正常 auto begin()const->decltype(a.begin()){返回a.begin();} //失败,不起作用:“decltype(a.end())”将是“迭代器”,但 //return语句返回“const_iterator” decltype(a.end())end()常量{返回a.end();} };

在第二次声明中,我们使用了传统风格。但是,由于该位置不允许使用此,编译器不会隐式使用它。因此
a.end()
使用静态声明的
a
类型来确定它要调用的
end
向量
重载是什么,它最终是非常量版本。

另一个优点是,当函数返回指向函数的指针时,后面的返回类型语法可以更可读。例如,比较

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

但是,有人认为,只需为函数指针引入类型别名,即可获得更好的可读性:

using FuncPtr = void (*)(int);
FuncPtr get_func_on(int i);

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

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

但是,有人认为,只需为函数指针引入类型别名,即可获得更好的可读性:

using FuncPtr = void (*)(int);
FuncPtr get_func_on(int i);

它主要用于参数上的
decltype