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, ledecay<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_wrapper
s.
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";
}