我什么时候想使用 auto&& 而不是 decltype(auto) 或 ->decltype(return-expr) 作为函数定义的返回类型?

问题描述 投票:0回答:1

采用三个返回纯右值、左值、x值的函数:

int   f();
int&  f(int);
int&& f(int, int);

并通过返回的函数调用它们

decltype(auto)

decltype(auto) returnsDecltypeOf(auto... x) {
    return f(x...);
}

这似乎按照人们期望的方式工作:

static_assert(std::is_same_v<decltype(returnsDecltypeOf()),    int>);
static_assert(std::is_same_v<decltype(returnsDecltypeOf(1)),   int&>);
static_assert(std::is_same_v<decltype(returnsDecltypeOf(1,1)), int&&>);

但是如果我将

decltype(auto)
更改为
auto&&
,

auto&& returnsAutoRefRef(auto... x) {
    return f(x...);
}

事情发生了变化:

static_assert(std::is_same_v<decltype(returnsAutoRefRef()),    int&&>);
static_assert(std::is_same_v<decltype(returnsAutoRefRef(1)),   int&>);
static_assert(std::is_same_v<decltype(returnsAutoRefRef(1,1)), int&&>);

我看到了明显的区别,

returnsAutoRefRef
总是返回一个引用,所以它可能会做错误的事情,例如在
f()
的情况下,它将通过
auto&&
返回值返回纯右值表达式,这将是一个悬空
int&&

因此,看起来

decltype(auto)
(或者,如果我们计划利用 SFINAE,甚至更好
-> decltype(return-expr)
)确实是将
return
表达式完美转发回调用者的方法。

所以我的问题是,我什么时候想回来

auto&&
?为什么我不能做
decltype(auto)


据我对 C++ 的理解,前导返回类型

decltype(auto)
与前导
auto
+ 尾随
-> decltype(return expression)
是一样的,除了后者是 SFINAE 友好的而前者不是 。现在,我不确定这个 SFINAE 特定的事情对问题的答案有多大影响!

c++ c++20 move-semantics sfinae perfect-forwarding
1个回答
0
投票

decltype(auto)
auto&&
不同的情况正好有两种。

正如您所指出的,当您返回纯右值时,

decltype(auto)
按值返回,并且
auto&&
返回悬空右值引用(可能不合需要)。

第二种情况是直接返回实体。例如:

struct X {
    int i;
    decltype(auto) return_entity() { return i; }
    decltype(auto) return_expression() { return (i); }
};

static_assert(std::is_same_v<decltype(X{}.return_entity()), int>);
static_assert(std::is_same_v<decltype(X{}.return_expression()), int&>);

(因为

decltype(i)
int
,但是
decltype((i))
int&
)。


所有其他场景中它们都是相同的。您可能需要使用

auto&&
来强调您正在返回参考信息,或者使用
decltype(auto)
来强调您正在完美转发某些内容。

作为示例,

std::forward_like
的文档显示为返回
auto&&
,因为它始终返回引用。

但是如果你可以返回纯右值,

decltype(auto)
显然是更好的选择。

© www.soinside.com 2019 - 2024. All rights reserved.