web-dev-qa-db-fra.com

Qu'est-ce que std :: decay et quand doit-il être utilisé?

Quelles sont les raisons de l'existence de std::decay ? Dans quelles situations est std::decay utile?

<blague> Il est évidemment utilisé pour décomposer les substances radioactives std::atomic entre des types non radioactifs. </ joke>

N2609 est le document qui a proposé std::decay. Le papier explique:

Tout simplement, decay<T>::type est la transformation du type d'identité, sauf si T est un type de tableau ou une référence à un type de fonction. Dans ces cas, le decay<T>::type renvoie un pointeur ou un pointeur sur une fonction, respectivement.

L’exemple de motivation est 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); 
}

qui accepte ses paramètres par valeur pour faire fonctionner les littéraux de chaîne:

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

S'il accepte ses paramètres par référence, alors T1 sera déduit sous forme de type tableau, puis construira un pair<T1, T2> sera mal formé.

Mais cela conduit évidemment à des inefficacités importantes. D'où la nécessité de decay, d'appliquer l'ensemble des transformations qui se produit lors de la transmission par valeur, ce qui vous permet d'obtenir l'efficacité de prendre les paramètres par référence, tout en obtenant les transformations de type nécessaires pour votre code. pour travailler avec des littéraux de chaîne, des types de tableau, des types de fonction, etc.:

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)); 
}

Remarque: il ne s'agit pas de la version actuelle de C++ 11 make_pair implémentation - le C++ 11 make_pair décompresse également std::reference_wrappers.

159
T.C.

Lorsque vous traitez avec des fonctions de modèle qui prennent des paramètres d'un type de modèle, vous avez souvent des paramètres universels. Les paramètres universels sont presque toujours des références d'une sorte ou d'une autre. Ils sont aussi qualifiés de const-volatile. En tant que tel, la plupart des caractères de type ne fonctionnent pas comme prévu:

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

La solution ici est d'utiliser 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

55
Mooing Duck