问题
Suppose you have a template argument T.
What are the differences between
add_cv_t<T>andconst volatile Tadd_const_t<T>andconst Tadd_volatile_t<T>andvolatile Tadd_lvalue_reference_t<T>andT&add_rvalue_reference_t<T>andT&&add_pointer_t<T>andT*?
Why should I use add_rvalue_reference_t<T> instead of T&& for example. Are there any rules when to choose which?
回答1:
add_cv_t<T>andconst volatile Tadd_const_t<T>andconst Tadd_volatile_t<T>andvolatile T
No difference; the definition of add_const<T>::type is just T const, for example.
add_lvalue_reference_t<T>andT&add_rvalue_reference_t<T>andT&&
T& and T&& are ill-formed when T is cv void, but these templates are well-formed, just giving the original type back.
add_pointer_t<T>andT*?
add_pointer_t<T> is equivalent to std::remove_reference<T>::type*. That is, if T is a reference type, it gives a pointer to the referenced type. On the other hand, T* will be ill-formed since you cannot have a pointer to a reference.
Which should you use?
- In general, the alias templates can be used to prevent deduction of
T. Of course, that means that if you want deduction, you should avoid them. - The alias templates can be used as template template arguments to a template that takes a type transformation as a parameter.
- The alias templates that differ in behaviour from alternatives like
T*are useful in generic code since they "do the right thing". For example, ifTis deduced from an argument of typeT&&, thenT*does the wrong thing when the argument is an lvalue, since it tries to declare a pointer to an lvalue reference. Butstd::add_pointer_t<T>will give a pointer to the actual type of the argument.
回答2:
According to what I see in STL source:
add_cv_t<T> and const volatile T- no difference
add_const_t<T> and const T - no difference
add_volatile_t<T> and volatile T - no difference
add_lvalue_reference_t<T> and T& - there is difference for example if T is non referenceable type void. add_lvalue_reference_t<void>::type = void and void& = compile-time error
add_rvalue_reference_t<T> and T&& - the same as above
add_pointer_t<T> and T* - difference when T is reference, because there is no such thing as pointer to reference. add_pointer_t<T> is equivalent to std::remove_reference<T>::type*
回答3:
In most cases, std::add_rvalue_reference_t<T> is equivalent to T&&. However, reference collapsing rules and the-rules-that-dictate-which-types-are-referenceable may have your code misbehave if not taked into account.
There are, however, some cases where the type static member type will be different due to T being a non-referenceable type. For example std::add_rvalue_reference_t<void> resolves to void, and (taking another template you mentioned as an example) std::add_pointer_t<T&> resolves to T* (if you want to invoke chaos, the required ritual is std::add_pointer_t<std::add_rvalue_reference_t<void>> :))
Respecting to uses, it may be used as a template template parameter to do some funky black magic. Anyway, stuff like std::is_rvalue_reference_t<T> or std::remove_reference_t<T> is usually more commonly used when manipulating the type's reference attributes.
来源:https://stackoverflow.com/questions/32147265/difference-between-add-lvalue-reference-tt-and-t