正确使用decltype作为尾随返回类型的方法

时间:2011-04-27 09:56:45

标签: c++ templates c++11 decltype perfect-forwarding

我经常看到这种形式的例子:

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生成的第二个代码是samel和第三个decltype(u + t)更直接,并且完全表达了程序员的意图,而不会带来“胆量”的实现。

您对此主题有何看法?

3 个答案:

答案 0 :(得分:3)

第一个版本更正确,因为它完全匹配函数体将返回的内容。正如已经指出的那样,根本无法保证

decltype(std::forward<T>(t) + std::forward<U>(u))

的类型相同
decltype(t + u)

可以说,这是一个非常落后的案例,但“正确”的方法是使用std :: forward。

答案 1 :(得分:2)

decltype(t + u)内,变量tu已经不再是右值引用,它们将被视为简单的左值引用,因此您需要aditional std::forward 。 (至少,这就是我理解它的方式。虽然可能是错的。)

答案 2 :(得分:2)

一般来说,我不能想到一个合理的用例会有区别,但我想你可以找到一些情况,其中操作对rvalue-references和rvalues有不同的实现,而语言规则没有规定不同重载的返回类型必须相同(即使常识会指示它)。

因此,在一般情况下,没有区别,并且在存在差异的情况下,这些案例需要额外的关注和注意,以解决比模板本身更糟糕的问题......

// sick corner case:
struct type {};
int operator+( type&& lhs, type&& rhs );
double operator+( type const & lhs, type const & rhs );

我可以考虑你想为rvalue-references提供不同的重载的情况(考虑一些提供operator+作为连接的列表的实现,然后使用rvalue引用的重载可以避免复制的成本只是用指针进行修改并将参数列表保留为空),但如果结果的类型取决于参数的l / rvalue-ness,则会完全混淆。

相关问题