Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between std::decay and std::remove_reference

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?

like image 459
Nex' Avatar asked Dec 18 '17 15:12

Nex'


2 Answers

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.

like image 62
Jodocus Avatar answered Sep 28 '22 04:09

Jodocus


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.

like image 39
Yakk - Adam Nevraumont Avatar answered Sep 28 '22 05:09

Yakk - Adam Nevraumont