参考折叠规则未按预期应用?

问题描述

我正在刷新关于C ++完美转发工作方式的记忆。我意识到,出于某种原因(例如,在处理实际上是左值的右值引用时),对std::forward调用被迫提供一个显式模板参数,但是当对实际代码进行完整性检查时,我对此感到惊讶(有点相关)方案:

#include <iostream>
#include <utility>
#include <type_traits>

template<class T>
T&& fwd(T& t) {
    return static_cast<T&&>(t);
}

template<class T>
T&& fwd(T&& t) {
    return static_cast<T&&>(t);
}

int main()
{
    int lnum = 3;
    if (std::is_rvalue_reference<decltype(fwd(lnum))>::value)
        std::cout << "It's rref." << std::endl;           // this get's printed on screen 
    else
        std::cout << "It's lref." << std::endl;

    return 0;
}

如果我理解引用正确折叠(并且我相信是这样),则类型推导应如下所示:

int& && fwd(int& & t) {                        
    return static_cast<int& &&>(t);         
}

导致

int& fwd(int& t) {                        
    return static_cast<int&>(t);         
}

显然不是这样。我在这里想念什么?

解决方法

首先,被调用的函数为T&& fwd(T& t)。因此,没有转发参考参数。参数是左值引用,推导的Tint。因此,没有崩溃的引用,并且静态类型转换产生int&&

如果被调用函数为T&& fwd(T&& t)(即,不存在更好的匹配重载),那么您对引用折叠的解释将是正确的(参数int& &&除外)也折叠int&),返回类型的确是左值引用。

,

实际上,没有引用崩溃发生。要注意的相关功能模板(即所选的一个)是:

template<class T>
T&& fwd(T& t) { // <-- not a forwarding reference
    return static_cast<T&&>(t);
}

请注意,此功能模板没有没有 转发引用 –函数参数t只是左值引用T& t

T模板参数推导为 int –不是int& –因为t不是转发引用,而只是左值引用。如果仅在上面的函数模板中将T替换为int,那么您将获得:

template<class T>
int&& fwd(int& t) {
    return static_cast<int&&>(t);
}

不应用引用折叠,因为此处没有这样的事情,否则它们最终会成为对引用的引用(例如int& &&int&& &&)。