Was sind die Gründe für die Existenz von std::decay
? In welchen Situationen ist das std::decay
sinnvoll?
decay_t<decltype(...)>
ist eine schöne Kombination, um zu sehen, was auto
sich daraus ergeben würde.
Was sind die Gründe für die Existenz von std::decay
? In welchen Situationen ist das std::decay
sinnvoll?
decay_t<decltype(...)>
ist eine schöne Kombination, um zu sehen, was auto
sich daraus ergeben würde.
Antworten:
<joke> Es wird offensichtlich verwendet, um radioaktive std::atomic
Typen in nicht radioaktive zu zerlegen. </ witz>
N2609 ist das vorgeschlagene Papier std::decay
. Das Papier erklärt:
Einfach ausgedrückt
decay<T>::type
ist dies die Transformation des Identitätstyps, es sei denn, T ist ein Array-Typ oder eine Referenz auf einen Funktionstyp. In diesen Fällendecay<T>::type
ergibt das einen Zeiger bzw. einen Zeiger auf eine Funktion.
Das motivierende Beispiel ist 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);
}
die ihre Parameter nach Wert akzeptierte, damit String-Literale funktionieren:
std::pair<std::string, int> p = make_pair("foo", 0);
Wenn es seine Parameter als Referenz akzeptiert hat, T1
wird es als Array-Typ abgeleitet und anschließend a erstelltpair<T1, T2>
schlecht geformt.
Dies führt jedoch offensichtlich zu erheblichen Ineffizienzen. Daher ist es erforderlich decay
, den Satz von Transformationen anzuwenden, der beim Übergeben von Werten auftritt, damit Sie die Effizienz der Referenzübernahme der Parameter erhalten und dennoch die Typtransformationen erhalten, die für die Arbeit Ihres Codes mit Zeichenfolgenliteralen erforderlich sind. Array-Typen, Funktionstypen und dergleichen:
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));
}
Hinweis: Dies ist nicht die eigentliche C ++ 11- make_pair
Implementierung. C ++ 11 make_pair
entpackt auch std::reference_wrapper
s.
Wenn Sie mit Vorlagenfunktionen arbeiten, die Parameter eines Vorlagentyps verwenden, haben Sie häufig universelle Parameter. Universelle Parameter sind fast immer Referenzen der einen oder anderen Art. Sie sind auch konstant flüchtig qualifiziert. Daher funktionieren die meisten Typmerkmale nicht wie erwartet:
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
Die Lösung hier ist zu verwenden 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";
}
decay
ist sehr aggressiv, z. B. wenn es auf eine Referenz auf ein Array angewendet wird, ergibt es einen Zeiger. Es ist normalerweise zu aggressiv für diese Art der Metaprogrammierung IMHO.
remove_const_t< remove_reference_t<T> >
möglicherweise eine benutzerdefinierte Metafunktion einschließen.