Roughly,
std::decay
a. removes cv-qualifiers,
b. removes references, and
c. converts arrays and functions to pointers.
This is usually a good-enough mental model.
If
decay was absent, the function might look like
1 2 3 4
|
template<typename T> auto f(T&& val) {
T* tmp = new T{ std::forward<T>(val) };
return tmp;
}
|
Which would fail where
T is a reference type, at least because
new creates objects and references aren't objects.
That suggests we could get away with just
remove_reference:
1 2 3 4 5
|
template<typename T> auto f(T&& val) {
using rawVal = typename std::remove_reference<T>::type;
rawVal* tmp = new rawVal{ std::forward<T>(val) };
return tmp;
}
|
But in that case, if
T is
int(&)[5] (as in line 12) and
rawVal is
int[5], the expression
new rawVal{ std::forward<T>(val) };
Has type
int* and can't be used to initialize
tmp whose type is
int(*)[5].
So in the OP
decay is needed to remove references and do the array-to-pointer conversion.
It's not strictly necessary to remove cv-qualifiers but that certainly makes the function more useful.