add_lvalue_reference_t<T> 和 T& 的区别
Difference between add_lvalue_reference_t<T> and T&
假设您有一个模板参数 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&&
例如。什么时候选哪个有什么规定吗?
根据我在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 = void
和 void&
= 编译时错误
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&&
当 T
为 cv 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>
这样的东西通常在操作类型的引用属性时更常用。
假设您有一个模板参数 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&&
例如。什么时候选哪个有什么规定吗?
根据我在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 = void
和 void&
= 编译时错误
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>
andconst volatile T
add_const_t<T>
andconst T
add_volatile_t<T>
andvolatile T
没有区别;例如,add_const<T>::type
的定义就是 T const
。
当
add_lvalue_reference_t<T>
andT&
add_rvalue_reference_t<T>
andT&&
T
为 cv void
时,T&
和 T&&
格式错误,但这些模板是良构的-形成,只是把原来的类型还回去。
add_pointer_t<T>
andT*
?
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>
这样的东西通常在操作类型的引用属性时更常用。