Quelles sont les raisons de l'existence de std::decay
? Dans quelles situations std::decay
utile ?
Réponses
Trop de publicités?<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));
}
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";
}