add_lvalue_reference_t<T> 和 T& 的区别

Difference between add_lvalue_reference_t<T> and T&

假设您有一个模板参数 T

两者有什么区别

为什么我应该使用 add_rvalue_reference_t<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*

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

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

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

T&T&& 格式错误,但这些模板是良构的-形成,只是把原来的类型还回去。

  • add_pointer_t<T> and T*?

add_pointer_t<T> 等同于 std::remove_reference<T>::type*。也就是说,如果 T 是一个引用类型,它会给出一个指向被引用类型的指针。另一方面,T* 将是错误格式的,因为您不能拥有指向引用的指针。

你应该使用哪个?

  • 一般来说,别名模板可以用来防止T的推导。当然,也就是说,如果你要扣分,就应该避开它们。
  • 别名模板可以用作将类型转换作为参数的模板的模板模板参数。
  • 别名模板在行为上与 T* 等替代方案不同,它们在通用代码中很有用,因为它们 "do the right thing"。例如,如果 T 是从 T&& 类型的参数推导出来的,那么当参数是左值时 T* 会做错事,因为它试图声明一个指向左值引用的指针.但是 std::add_pointer_t<T> 会给出一个指向参数实际类型的指针。

在大多数情况下,std::add_rvalue_reference_t<T> 等同于 T&&。但是,如果不考虑 reference collapsing rules 和规定哪些类型可引用的规则,您的代码可能会出现错误行为。

但是,在某些情况下,由于 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> or std::remove_reference_t<T> 这样的东西通常在操作类型的引用属性时更常用。