Search code examples
c++templatesc++11generic-programming

Difference between add_lvalue_reference_t<T> and T&


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?


Solution

    • add_cv_t<T> and const volatile T
    • add_const_t<T> and const T
    • add_volatile_t<T> and volatile T

    No difference; the definition of add_const<T>::type is just T const, for example.

    • add_lvalue_reference_t<T> and T&
    • add_rvalue_reference_t<T> and T&&

    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> and T*?

    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, 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.