172 votes

Qu'est-ce que std::decay et quand l'utiliser ?

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

173voto

T.C. Points 22510

<joke>Il est évidemment utilisé pour la désintégration radioactive. <code>std::atomic</code> en des types non radioactifs. </joke>

N2609 est le document qui a proposé std::decay . L'exemple motivant 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 chaînes de caractères :

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

S'il a accepté ses paramètres par référence, alors T1 sera déduit comme étant un type de tableau, et ensuite la construction d'un fichier pair<T1, T2> seront mal formées.

Mais cela conduit évidemment à des inefficacités importantes. D'où la nécessité de decay pour appliquer l'ensemble des transformations qui se produisent lors d'un passage 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 que votre code fonctionne avec des chaînes de caractères, des types de tableaux, des types de fonctions, 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)); 
}

63voto

Mooing Duck Points 27497

Lorsque vous traitez 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 également qualifiés de const-volatiles. En tant que tels, la plupart des traits de type ne fonctionnent pas sur eux comme on pourrait s'y attendre :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X