Suppose you have a template argument T
.
What are the differences between
add_cv_t<T>
and const volatile T
add_const_t<T>
and const T
add_volatile_t<T>
and volatile T
add_lvalue_reference_t<T>
and T&
add_rvalue_reference_t<T>
and T&&
add_pointer_t<T>
and T*
?Why should I use add_rvalue_reference_t<T>
instead of T&&
for example. Are there any rules when to choose which?
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?
T
. Of course, that means that if you want deduction, you should avoid them.T*
are useful in generic code since they "do the right thing". For example, if T
is deduced from an argument of type T&&
, then T*
does the wrong thing when the argument is an lvalue, since it tries to declare a pointer to an lvalue reference. But std::add_pointer_t<T>
will give a pointer to the actual type of the argument.