When template metaprogramming in C++, I often run into something like the following:
template <typename T>
S<T> make_wrapper(T&& t) { return S<T>(std::forward<T>(t)); }
I know I should use something like std::decay in the return type, but why wouldn't std::remove_reference work as well? What's the difference here? What about std::remove_cvref?
Consider for example
#include <type_traits>
int main()
{
    static_assert(std::is_same_v<
        std::decay_t<const int&>, 
        std::remove_reference_t<const int&>
    >); // int != const int
}
std::decay will remove any cv-qualifer, remove_reference won't. It will just strip the "reference" part of the type.
From the reference:
Applies lvalue-to-rvalue, array-to-pointer, and function-to-pointer implicit conversions to the type T, removes cv-qualifiers, and defines the resulting type as the member typedef type.
Therefore std::decay will perform way more type conversions than std::remove_reference.
There are also further type modifiers for more nuanced applications that will only perform selected parts of the set of possible transformations decay does, like remove_cv, remove_volatile or, in C++20, remove_cvref.
Removing reference would leave const and volatile.  If that is what you want, then it will suffice.
Removing cvref does most of what decay does, but doesn't convert function types and array types to pointers.
decay converts a type in a way that you could reasonably store a copy of it in an array or in a struct, or return it from or pass it to a function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With