模板参数的引用变量引起的问题

M. *_* E. 4 c++ templates lvalue rvalue-reference c++11

以下小例子显示了我的问题:

template<class T> struct X
{
    static void xxx(T& x) { }
    static void xxx(T&& x) { }
};

int main(int argc, char** argv)
{
    int x = 9;
    X<int>::xxx(x); // OK.
    X<int&>::xxx(x); // ERROR!
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

错误消息(GCC):

错误:'static void X :: xxx(T &&)[with T = int&]'无法重载
错误:'static void X :: xxx(T&)[with T = int&]'

为什么?T = int&--->是T&替换int&&static void xxx(T& x)

如果问题的答案是肯定的,那么:

  • T& 不是左值引用,它变成了右值引用!
  • 以下代码应该工作:

但它没有:

template<class T> struct X
{
    static void xxx(T& x) { }
};

int main(int argc, char** argv)
{
    X<int&>::xxx(2); // ERROR!
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

错误消息(GCC):

错误:没有匹配函数来调用'X :: xxx(int)'
注意:候选者是:static void X :: xxx(T&)[with T = int&]

然后T&使用T = int&不等于T&&并且不是rvalue-reference.但如果不是,为什么第一个例子不起作用?(这是一个递归问题!)


但是指针类型没有出现类似的问题:

#include <iostream>

template<class T> struct X
{
    static void xxx(T* x) { std::cout << **x << std::endl; }
};

int main(int argc, char** argv)
{
    int x = 10;
    int* xx = &x;
    X<int*>::xxx(&xx); // OK. call X<int*>::xxx(int**)
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

为什么这种行为的参考不同?

Jam*_*lis 10

C++ 11语言标准在§8.3.2[dcl.ref]/6(为了可读性而重新格式化)中解释了它的工作原理:

如果typedef,type template-parameterdecltype-speci fi er表示作为类型TR引用的类型T,

  • 尝试创建类型"对cv的 左值引用TR"创建类型"左值引用T"
  • 尝试创建"对cv的 rvalue引用TR"类型会创建该类型TR.

让我们考虑你的榜样(我已经改名为你TTR因此它的语言相匹配以上):

template<class TR> struct X
{
    static void xxx(TR& x)  { }
    static void xxx(TR&& x) { }
};
Run Code Online (Sandbox Code Playgroud)

如果我们尝试XTR = int&(so,T = int)实例化,实例化xxx如下:

static void xxx(TR& x)  { }   -->   static void xxx(int& x) { }
static void xxx(TR&& x) { }   -->   static void xxx(int& x) { }
Run Code Online (Sandbox Code Playgroud)

在第一种情况下,我们尝试创建一个"左值引用TR",它成为"左值引用T". T是的int,所以参数类型变成了int&.

在第二种情况下,我们试图创建一个"右值参照TR",其变TR,这是int&.

两个重载的参数类型相同,因此错误.