在C ++ 14中引入auto
返回类型,是否有任何实际情况需要尾随返回类型,或者它在C ++ 14和17中完全过时了?
答案 0 :(得分:11)
考虑...
auto f(int x)
{
if (x == 2)
return 3;
return 2.1;
}
...这有一个不明确的返回类型 - int
或double
。显式返回类型 - 无论是前缀还是尾随 - 可以消除歧义,并将return
参数强制转换为返回类型。
decltype
,sizeof
等,特别是尾随返回类型也很有用:
auto f(int x) -> decltype(g(x))
{
if (x == 2)
return g(x);
return 2;
}
答案 1 :(得分:10)
尾随返回类型为您提供SFINAE支持。推迟返回类型永远不会导致错误,只是替换失败。
这允许编译器不必编译整个任意函数体,然后干净地退出以确定是否适用过载。
答案 2 :(得分:2)
除了您需要使用它(此处的其他答案提供了很好的示例)之外,您可以将其用于清晰度,以明确说明函数返回的内容。一旦你意识到(希望很快)阅读代码至少与编写代码一样重要,这一点非常重要。
考虑:
auto split(gsl::cstring_span str)
{
...
...
auto tokens = std::vector<gsl::cstring_span>();
...
...
for (...) {
...
...
...
}
...
return tokens;
}
与
auto split(gsl::cstring_span str) -> std::vector<gsl::cstring_span>();
{
... doesn't even matter
}
我不应该在实现中查看函数的合同是什么。我可以通过查看第一个例子来猜测返回类型是什么,但这些假设在编程中是危险的。我必须扫描实现以确保在调用函数时收到的内容。在第二个例子中,我清楚地说明了界面。我并不关心实施,因为名称是不言自明的,因此我根本不必查看定义。
进一步考虑这个最糟糕的例子。让我们找出这个函数返回的内容:
auto split(const char* str)
{
return split(gsl::cstring_span(str));
}
好的,现在搜索那个重载:
auto split(gsl::cstring_span str)
{
return split_impl(str);
}
Okey ......,现在让我们遵循:
auto split_impl(gsl::cstring_span str)
{
return split_impl(str, ::isspace);
}
你是开玩笑吧。
所以我希望你明白这一点。
我并不是说总是使用显式返回类型,我说要考虑知道返回类型应该快速简单地看一下该函数。有时,对于单行,可以从身体中发现。有时,可以从名称中安全地猜到(例如is_empty()
明确返回bool
)。其他时候,您需要明确地命名它。让开发人员以后使用代码的生活更简单,特别是因为那个人最终不可避免地会成为你。