ChatGPT解决这个技术问题 Extra ChatGPT

尾随返回类型语法样式是否应该成为新 C++11 程序的默认值? [关闭]

关闭。这个问题是基于意见的。它目前不接受答案。想改进这个问题?更新问题,以便可以通过编辑这篇文章用事实和引用来回答它。 5年前关闭。改进这个问题

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

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

目前这个函数将被声明为:

int func_name(int x, int y);

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

然而,这种新风格应该在新的 C++11 程序中无处不在,还是只在需要时使用?

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

它主要用于 decltype 的论点。
CatPlusPlus 所说的:在您的示例中使用它没有多大意义
@Cat Plus Plus 这意味着您可以保留 C++03 中的内容,除非您需要派生返回类型?
丑陋的必须在每个功能前指定“自动”。这就像 C++ 对 python 的“def”的活泼回答吗?
我只会在需要时使用它(例如在返回类型中使用 decltype 时)。我认为这是首先引入这种语法的重点。

C
Community

在某些情况下,您必须使用尾随返回类型。最值得注意的是,如果指定了 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
{
    // ...
}

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

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

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

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

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

我在 CxxReflect 中到处都使用了尾随返回类型,因此,如果您正在寻找代码如何始终如一地使用它们的示例,您可以查看那里(例如,the type class)。


看起来还没有达成共识,但是用新样式来看看 CxxReflect 很有趣。
嗨,詹姆斯。根据 C++14 标准,这个答案可能会更准确。
@DrewDormann 您会添加/更改什么?
对齐实际上是一个很大的优势,以至于我希望有一个新的 'func' 关键字来替换这里无意义的 'auto'。
#define fn auto,您可以编写类似于 Rust 的代码 ;-)
J
Johannes Schaub - litb

除了别人说的,尾随返回类型还允许使用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(); }
};

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


虽然这是一个很好/简洁的概念演示(在返回类型中使用成员),但很有趣,因为在 C++14 中指定类型在没有转换的内联定义中完全是多余的;我们现在可以只使用完整的返回类型扣除。 :P
s
s3rvac

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

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

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

但是,有人可以争辩说,只需为函数指针引入一个类型别名就可以实现更好的可读性:

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

P
PiotrNycz

请参阅这篇不错的文章: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;
}

并且从 Alex Alllain 的文章“因为返回值在函数的末尾,而不是在它之前,你不需要添加类范围”中也有精彩的解释。

与这种意外忘记类范围的可能情况相比,并且为了更大的灾难,在全局范围内定义了另一个 PersonType:

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

我不确定这是否属于“灾难”类别:如果类型错误,则代码将无法编译。运行时错误可能会造成灾难性的后果;编译时错误,不是那么多。
@JamesMcNellis 比较编译器输出:prog.cpp:13:12: error: prototype for 'PersonType Person::getPersonType()' does not match any in class 'Person'prog.cpp:13:1: error: 'PersonType' does not name a type 编译器的第一个错误,至少对我来说,更难理解。
我个人不同意,我发现第二条消息更难阅读,我宁愿让实现看起来像声明。