why use std::decay?

Why is it necessary to use std::decay and std::forward here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
	template<typename T>
	auto f(T&& val)
	{
		using rawVal = std::decay<T>::type;
		rawVal* tmp = new rawVal{ std::forward<T>(val) };
		return tmp;
	}

	void use()
	{
		int vec[5];
		auto a = f(vec);
		auto b = f(5);
	}


Thanks!
Last edited on
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.
Last edited on
Topic archived. No new replies allowed.