提问人:Enlico 提问时间:11/6/2023 更新时间:11/6/2023 访问量:92
我什么时候想使用 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?
问:
取三个函数返回 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 表达式,这将是一个悬空的 .returnsAutoRefRef
f()
auto&&
int&&
因此,看起来(或者,如果我们打算利用 SFINAE,甚至更好)确实是将表达式完美地转发回调用方的方法。decltype(auto)
-> decltype(return-expr)
return
所以我的问题是,我什么时候想回来?为什么我不能做?auto&&
decltype(auto)
据我了解 C++,前导返回类型与前导 + 尾随是一回事,除了后者对 SFINAE 友好而前者不友好。现在,我不确定这个特定于 SFINAE 的东西对问题的答案有多大影响!decltype(auto)
auto
-> decltype(return expression)
答:
正好有两种情况与 不同。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)
int
decltype((i))
int&
在所有其他情况下,它们都是相同的。你可能想用它来强调你正在返回一个参考,或者强调你是完美的转发者。auto&&
decltype(auto)
例如,std::forward_like
的此文档显示为返回,因为它始终返回引用。auto&&
但是,如果您可能返回 prvalue,显然是可取的。decltype(auto)
评论
auto&&
将应用与模板扣除相同的扣除规则。当然,您总是以这种方式获得引用类型。T&&
auto&&