Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is std::decay and when it should be used?

People also ask

What is std:: decay?

std::decay 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 . Formally: If T names the type "array of U " or "reference to array of U ", the member typedef type is U*.

What does decay mean in c++?

C++ProgrammingServer Side Programming. The loss of type and dimensions of an array is known as array decay. It occurs when we pass the array into a function by pointer or value. First address is sent to the array which is a pointer. That is why, the size of array is not the original one.

What is the purpose of std :: any?

std::any. The class any describes a type-safe container for single values of any copy constructible type. 1) An object of class any stores an instance of any type that satisfies the constructor requirements or is empty, and this is referred to as the state of the class any object.


<joke>It's obviously used to decay radioactive std::atomic types into non-radioactive ones.</joke>

N2609 is the paper that proposed std::decay. The paper explains:

Simply put, decay<T>::type is the identity type-transformation except if T is an array type or a reference to a function type. In those cases the decay<T>::type yields a pointer or a pointer to a function, respectively.

The motivating example is C++03 std::make_pair:

template <class T1, class T2> 
inline pair<T1,T2> make_pair(T1 x, T2 y)
{ 
    return pair<T1,T2>(x, y); 
}

which accepted its parameters by value to make string literals work:

std::pair<std::string, int> p = make_pair("foo", 0);

If it accepted its parameters by reference, then T1 will be deduced as an array type, and then constructing a pair<T1, T2> will be ill-formed.

But obviously this leads to significant inefficiencies. Hence the need for decay, to apply the set of transformations that occurs when pass-by-value occurs, allowing you to get the efficiency of taking the parameters by reference, but still get the type transformations needed for your code to work with string literals, array types, function types and the like:

template <class T1, class T2> 
inline pair< typename decay<T1>::type, typename decay<T2>::type > 
make_pair(T1&& x, T2&& y)
{ 
    return pair< typename decay<T1>::type, 
                 typename decay<T2>::type >(std::forward<T1>(x), 
                                            std::forward<T2>(y)); 
}

Note: this is not the actual C++11 make_pair implementation - the C++11 make_pair also unwraps std::reference_wrappers.


When dealing with template functions that take parameters of a template type, you often have universal parameters. Universal parameters are almost always references of one sort or another. They're also const-volatile qualified. As such, most type traits don't work on them as you'd expect:

template<class T>
void func(T&& param) {
    if (std::is_same<T,int>::value) 
        std::cout << "param is an int\n";
    else 
        std::cout << "param is not an int\n";
}

int main() {
    int three = 3;
    func(three);  //prints "param is not an int"!!!!
}

http://coliru.stacked-crooked.com/a/24476e60bd906bed

The solution here is to use std::decay:

template<class T>
void func(T&& param) {
    if (std::is_same<typename std::decay<T>::type,int>::value) 
        std::cout << "param is an int\n";
    else 
        std::cout << "param is not an int\n";
}

http://coliru.stacked-crooked.com/a/8cbd0119a28a18bd