[英]Correct way to use decltype as trailing return type
我经常看到这种形式的例子:
template <typename T, typename U>
auto add(T&& t, U&& u) -> decltype(std::forward<T>(t) + std::forward<U>(u))
{
return std::forward<T>(t) + std::forward<U>(u);
}
但我敢说这是更好更正确的方法:
template <typename T, typename U>
auto add(T&& t, U&& u) -> decltype(t + u)//no forwarding here
{
return std::forward<T>(t) + std::forward<U>(u);
}
为什么? 首先,这个例子中的 decltype 只需要推断返回类型,所以 (t + u) 是返回类型而不是 (std::forward(t) + std::forward(u)),第二个代码由两个 ver 生成同样,第三个 decltype(u + t) 更直接,准确地表达了程序员的意图,而没有带出实现的“胆量”。
你对这个话题有什么看法?
第一个版本更正确,因为它与 function 主体将要返回的完全匹配。 正如已经指出的那样,根本无法保证
decltype(std::forward<T>(t) + std::forward<U>(u))
将与
decltype(t + u)
可以说,这是一个非常极端的情况,但“正确”的方法是使用 std::forward。
在decltype(t + u)
中,变量t
和u
已经不再是右值引用,它们将被视为简单的左值引用,因此您需要额外的std::forward
。 (至少,这就是我的理解。虽然可能是错的。)
一般来说,我想不出一个明智的用例会有所不同,但我想你可以找到一些情况,其中操作对右值引用和右值有不同的实现,并且语言规则并没有规定返回不同重载的类型必须相同(即使常识会决定它)。
所以,在一般情况下,不会有任何区别,而在有区别的情况下,那些情况需要格外小心和注意,因为问题比模板本身要糟糕得多......
// sick corner case:
struct type {};
int operator+( type&& lhs, type&& rhs );
double operator+( type const & lhs, type const & rhs );
我可以考虑您希望为右值引用提供不同重载的情况(考虑提供operator+
作为连接的列表的某些实现,然后带有右值引用的重载可以避免复制的成本,只需使用指针进行修改并离开参数列表为空),但如果结果的类型取决于 arguments 的 l/rvalue-ness,那将完全令人困惑。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.