繁体   English   中英

为什么左值引用不能绑定到 const const“转发引用”?

[英]Why can't lvalue references bind to const const "forwarding references"?

“转发引用”用引号引起来,因为const限定的转发引用实际上并不是转发引用,但我想明确表示我特指的是函数模板。

采取以下测试功能(代码重复以避免:

#include <iostream>
#include <type_traits>
#include <typeinfo>

using namespace std;

template <typename T, typename U> void print_types() {
  cout << (is_const_v<remove_reference_t<T>> ? "const " : "")
       << typeid(T).name()
       << (is_rvalue_reference_v<T>   ? " &&"
           : is_lvalue_reference_v<T> ? " &"
                                      : "")
       << ", " << (is_const_v<remove_reference_t<U>> ? "const " : "")
       << typeid(U).name()
       << (is_rvalue_reference_v<U>   ? " &&"
           : is_lvalue_reference_v<U> ? " &"
                                      : "")
       << endl;
}

template <typename T> void print_rvalue_reference(T &&t) {
  print_types<T, decltype(t)>();
}

template <typename T> void print_const_rvalue_reference(const T &&t) {
  print_types<T, decltype(t)>();
}

int main() {
  int i = 1;
  const int j = 1;

  print_rvalue_reference(1); // int, int &&
  print_rvalue_reference(i); // int &, int &
  print_rvalue_reference(j); // const int &, const int &

  print_const_rvalue_reference(1); // int, const int &&
  print_const_rvalue_reference(i); // error
  print_const_rvalue_reference(j); // error
}

首先,我想指出print_rvalue_reference(j)仅起作用,因为print_rvalue_reference从不在非const上下文中使用t 如果不是这种情况,模板实例化将失败。

我很困惑为什么main的最后两个调用会在编译过程中导致错误。 参考折叠允许using T = int &; const T && using T = int &; const T &&变为int &using T = const int &; const T && using T = const int &; const T &&变为const int & ,这意味着print_const_rvalue_reference<int &>(i)print_const_rvalue_reference<const int &>(j)是有效的。

为什么print_const_rvalue_reference(j)演绎吨至是int而不是const int &print_rvalue_reference(j)演绎吨至是const int & (真)转发引用是否特殊情况下产生int &而不是int作为其推导指南的一部分?

实际的转发引用确实是特殊情况以推导出引用类型。 [temp.deduct.call]/3

如果P是CV-合格的类型,顶级CV-预选赛P的类型被忽略类型推演。 如果P是引用类型,则使用P引用的类型进行类型推导。 ... 如果P是转发引用并且参数是左值,则使用“左值引用A ”类型代替A进行类型推导。

因此,在Pconst T&& (不是转发引用)的情况下,它被转换为const T并且参数是否是左值不会影响类型推导,因为值类别不是参数的类型。 相反,推导过程只是试图找到T使得const T与参数的类型相同(可能带有额外的 cv 限定)。 ij的情况下,这意味着T被推导出为int并且参数类型是const int&&

但是在特殊的转发引用情况下,虽然P仍然从T&&转换为T ,但它最初是转发引用的事实导致参数类型替换为相应的左值引用类型(如果参数是左值)。 因此,在i的情况下,转换后的参数类型是int& ,而在j的情况下,它是const int& 在这两种情况下, T都以使其与转换后的参数类型相同的方式推导,这意味着T被推导为引用类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM