C++ 模板显式右值类型

C++ Template explicit rvalue type

#include <iostream>

using namespace std;

namespace mine {

    template <typename T>
    struct remove_rval {
        using type = T;
    };

    template <typename T>
    struct remove_rval<T&&> {
        using type = T;    
    };

    template <typename T>
    void g(const T& = typename remove_rval<T>::type())
       cout << __PRETTY_FUNCTION__ << endl;        
    }
}

int main()
{
    
    mine::g<int&&>(); // doesn't work, because of explicit template?
    const int& i2 = mine::remove_rval<int&&>::type(); // works, sanity check
    
    return 0;
}

我写的函数模板编译失败。根据我对 c++ 的理解,您可以将右值分配给常量左值引用。但是,在这种情况下,就像推导类型在分配函数默认值时忽略 'const' 限定符一样。这是为什么?

void g(const T& = typename remove_rval<T>::type())

T = U&& 时,引用折叠规则使 const T& 等于 U&。 Lvalue-references 无法绑定到像 remove_rval<T>::type() 这样的临时对象。您可以简单地将 int 作为模板参数传递,参数的类型将正确地为 const int&.

来自 dcl.ref/p6:

If a typedef-name ([dcl.typedef], [temp.param]) or a decltype-specifier ([dcl.type.decltype]) denotes a type TR that is a reference to a type T, an attempt to create the type lvalue reference to cv TR creates the type lvalue reference to T, while an attempt to create the type rvalue reference to cv TR creates the type TR.

因此在您的示例中,T = int&& 时: const T& 折叠为 T&(即 int&)和 而不是 const T&(即 const int&)以上引用的声明。而且由于我们不能将 rvalueremove_rval<T>::type() 绑定到 non-const 左值引用 ,你会得到提到的错误.

因此,即使 g 中函数参数的形式是 对 const T 的引用,又名 const 左值引用(即 const T&),第一次调用 g 实例化 g 引用 non-const T 又名 non-const 左值引用 (即 T& =int&) 作为参数:

template<>
void g<int &&>(int&)
{
  //operator<< called here
}

并且因为参数是 int&,我们不能像 remove_rval<int&&>::type() 这样的 rvalue 绑定到那个参数。