【问题标题】:Problem by a reference variable of a template parameter模板参数的引用变量的问题
【发布时间】:2010-08-22 17:27:44
【问题描述】:

下面的小例子说明了我的问题:

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;
}

错误信息 (GCC):

错误:'static void X::xxx(T&&) [with T = int&]' 不能重载
错误:带有'static void X::xxx(T&) [with T = int&]'

为什么? T = int&amp; ---> T&amp;static void xxx(T&amp; x) 中被int&amp;&amp; 替换了吗?

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

  • T&amp; 不是左值引用,而是成为右值引用!
  • 下面的代码应该可以工作:

但它没有:

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

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

错误信息 (GCC):

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

那么T&amp;T = int&amp; 不等于T&amp;&amp; 并且不是右值引用。但如果不是,为什么第一个例子不起作用? (这是一个递归问题!)


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

#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;
}

为什么引用在这种行为中有所不同?

【问题讨论】:

  • 我的头好痛。这么多和号。
  • &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&& @詹姆斯&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 跨度>

标签: c++ templates c++11 rvalue-reference lvalue


【解决方案1】:

C++11 语言标准在 §8.3.2[dcl.ref]/6 中解释了其工作原理(为便于阅读重新格式化):

如果 typedef、类型 template-parameterdecltype-specifier 表示类型 TR 是对类型 T 的引用,

  • 尝试创建类型“对 cv TR 的左值引用”会创建类型“对T 的左值引用”
  • 尝试创建类型“对 cv TR 的右值引用”会创建类型 TR

让我们考虑您的示例(我已将您的 T 重命名为 TR,以便与上述语言匹配):

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

如果我们尝试用TR = int&amp; 实例化X(所以,T = int),xxx 的实例化如下:

static void xxx(TR& x)  { }   -->   static void xxx(int& x) { }
static void xxx(TR&& x) { }   -->   static void xxx(int& x) { }

在第一种情况下,我们尝试创建一个“对TR 的左值引用”,它变成一个“对T 的左值引用”。 Tint,所以参数类型变成int&amp;

在第二种情况下,我们尝试创建一个“对TR 的右值引用”,它变为TR,即int&amp;

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

【讨论】:

  • 我有 70% 的人相信你已经完全记住了这些规格
  • 谢谢表达TR的意思。
  • 这是使std::forward 起作用的规则吗?也就是说,每个 C++0x 程序员都必须知道这一点...... :)
  • @UncleBens:这条规则不是为右值引用而制定的,它可以追溯到右值引用之前。在 C++98 中,“尝试创建对引用类型的引用”会导致类型推导失败(第 14.8.2/2 节)。 CWG Defect 106 被提出,它的分辨率为我们提供了我在这里描述的行为(仅用于左值引用)。我原以为这条规则包含在 C++03 中(C++ 模板 中的 Vandevoorde 和 Josuttis 预计会如此),但事实并非如此。不过,forward 需要这条规则才能工作。
  • 这种行为被称为 reference collapsing(我只记得;这让我整天发疯,我不记得这叫什么了)。
猜你喜欢
  • 2012-11-05
  • 2011-09-28
  • 1970-01-01
  • 1970-01-01
  • 2021-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-19
相关资源
最近更新 更多