问题
Suppose you have a template argument T
.
What are the differences between
add_cv_t<T>
andconst volatile T
add_const_t<T>
andconst T
add_volatile_t<T>
andvolatile T
add_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 T
add_const_t<T>
andconst T
add_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, ifT
is 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