Difference between add_lvalue_reference_t<T> and T&

Difference between add_lvalue_reference_t<T> and T&

本文关键字:amp gt lt and between add lvalue reference Difference      更新时间:2023-10-16

假设您有一个模板参数T

  • add_cv_t<T>const volatile T
  • add_const_t<T>const T
  • add_volatile_t<T>volatile T
  • add_lvalue_reference_t<T>T&
  • add_rvalue_reference_t<T>T&&
  • add_pointer_t<T>T* ?

为什么我应该使用add_rvalue_reference_t<T>而不是T&&,例如。选择哪个有什么规则吗?

  • add_cv_t<T>const volatile T
  • add_const_t<T>const T
  • add_volatile_t<T>volatile T

没有区别;例如,add_const<T>::type的定义就是T const

  • add_lvalue_reference_t<T>T&
  • add_rvalue_reference_t<T>T&&
Tcv void时,

T&T&&是病态的,但这些模板是格式良好的,只是返回原始类型。

  • add_pointer_t<T>T* ?

add_pointer_t<T>相当于std::remove_reference<T>::type*。也就是说,如果T是引用类型,它给出一个指向被引用类型的指针。另一方面,T*将是病态的,因为你不能有指向引用的指针。

你应该用哪个?

  • 一般情况下,可以使用别名模板来防止扣T。当然,这意味着如果你想要推理,你应该避免它们。
  • 别名模板可以用作模板模板的参数,以类型转换作为参数。
  • T*等替代品行为不同的别名模板在泛型代码中很有用,因为它们"做正确的事情"。例如,如果T是从T&&类型的参数推导出来的,那么当参数是左值时,T*会做错误的事情,因为它试图声明一个指向左值引用的指针。但是std::add_pointer_t<T>会给出一个指向实参实际类型的指针。

根据我在STL源代码中看到的:

add_cv_t<T>const volatile T -无差异

add_const_t<T>const T -无差异

add_volatile_t<T>volatile T -无差异

add_lvalue_reference_t<T>T& -有区别,例如,如果T是不可引用的类型void。add_lvalue_reference_t<void>::type = voidvoid& =编译时错误

add_rvalue_reference_t<T>T&& -同上

add_pointer_t<T>T* -当T是引用时的差异,因为没有指向引用的指针。add_pointer_t<T>相当于std::remove_reference<T>::type*

大多数情况下,std::add_rvalue_reference_t<T>等同于T&&。但是,如果不考虑引用折叠规则和指定哪些类型是可引用的规则,可能会使您的代码出错。

但是,在某些情况下,由于T是不可引用的类型,type静态成员类型会有所不同。例如,std::add_rvalue_reference_t<void>解析为void,并且(以您提到的另一个模板为例)std::add_pointer_t<T&>解析为T*(如果您想调用混乱,所需的仪式是std::add_pointer_t<std::add_rvalue_reference_t<void>>:))

就用途而言,它可能被用作模板模板参数来做一些奇怪的黑魔法。无论如何,std::is_rvalue_reference_t<T>std::remove_reference_t<T>之类的东西在操作类型的引用属性时通常更常用。