Is `std::decay_t decay_copy(T&&)` equivalent to `auto decay_copy(auto&&)`?

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3255.html defines decay_copy as follows:

template<typename T>
std::decay_t<T> decay_copy(T&& v)
{ 
    return std::forward<T>(v);
}

I just wonder:

Is it equivalent to the following simpler one?

auto decay_copy(auto&& v)
{
    return v;
}

Answer

It wasn’t in 2011, because:

  • We didn’t have auto return type deduction for functions (that’s a C++14 feature), and
  • We didn’t have auto&& parameters for functions (that’s a C++20 feature), and
  • Rvalue references were not implicitly moved from in return statements (that’s also a C++20 feature)

But in C++20, yes, that is now a valid way to implement decay_copy. auto deduction does decay, return v; implicitly forwards, and everything else is the same.


I guess technically there’s an edge case like:

struct X {
    X();
    X(X&);
};

With the original formulation of decay_copy(X{}), this is ill-formed (there’s no viable constructor for constructing an X from an rvalue X). With the new formulation under the existing C++20 rules, it becomes well formed and invokes the non-const copy constructor (because we do this two-step overload resolution).

If P2266 is adopted though, then they would be exactly equivalent because return v; would always treat v as an rvalue, exactly as the existing formulation does.