假设您有一个模板参数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&&
。有什么规则可供选择吗?
答案 0 :(得分:13)
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&&
T&
cv T&&
时, T
和void
格式不正确,但这些模板格式正确,只是给出了原型返回。
add_pointer_t<T>
和T*
?
add_pointer_t<T>
相当于std::remove_reference<T>::type*
。也就是说,如果T
是引用类型,则它会提供指向引用类型的指针。另一方面,由于你没有指向引用的指针,T*
将是格式错误的。
你应该使用哪种?
T
。当然,这意味着如果你想要扣除,你应该避免它们。T*
等替代方案不同的别名模板在通用代码中非常有用,因为它们可以做正确的事情&#34;。例如,如果从T
类型的参数推导出T&&
,那么当参数是左值时,T*
会做错误的事情,因为它试图声明一个指向左值参考的指针。但是std::add_pointer_t<T>
会给出一个指向参数实际类型的指针。答案 1 :(得分:3)
根据我在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*
答案 2 :(得分:0)
在大多数情况下,std::add_rvalue_reference_t<T>
相当于T&&
。但是,如果不考虑,reference collapsing rules和那些规定哪些类型可引用的规则可能会使您的代码行为异常。
但是,由于type
是不可引用的类型,因此T
静态成员类型会有所不同。例如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>
之类的东西通常更常用。