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

When would I want to use auto&& instead of decltype(auto) or ->decltype(return-expr) for the return type of a function definition?

提问人:Enlico 提问时间:11/6/2023 更新时间:11/6/2023 访问量:92

问:

取三个函数返回 prvalue、lvalue、xvalue:

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&&>);

我看到了总是返回引用的明显区别,因此它可能会做错误的事情,例如,在 的情况下,它将通过返回值返回一个 prvalue 表达式,这将是一个悬空的 .returnsAutoRefReff()auto&&int&&

因此,看起来(或者,如果我们打算利用 SFINAE,甚至更好)确实是将表达式完美地转发回调用方的方法。decltype(auto)-> decltype(return-expr)return

所以我的问题是,我什么时候想回来?为什么我不能做?auto&&decltype(auto)


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

C++ C++20 移动语义 sfinae 完美转发

评论

0赞 Rerito 11/6/2023
auto&&将应用与模板扣除相同的扣除规则。当然,您总是以这种方式获得引用类型。T&&
2赞 NathanOliver 11/6/2023
我想说的是,将其用作返回类型是绝对不正确的。它锁定了您通过引用返回,并且返回右值引用的用例有限。auto&&
0赞 康桓瑋 11/6/2023
这是差异的教科书示例,请参阅 stackoverflow.com/questions/67282639/...
0赞 user12002570 11/6/2023
相关:decltype(auto) vs auto&&,以执行函数返回类型的泛型处理

答:

4赞 Artyer 11/6/2023 #1

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

正如您所指出的,当您返回 prvalue 时,将按值返回,并返回一个悬空的右值引用(可能是不希望的)。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)intdecltype((i))int&


所有其他情况下,它们都是相同的。你可能想用它来强调你正在返回一个参考,或者强调你是完美的转发者。auto&&decltype(auto)

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

但是,如果您可能返回 prvalue,显然是可取的。decltype(auto)