Jakie są powody istnienia std::decay? W jakich sytuacjach std::decayprzydaje się?
decay_t<decltype(...)>to fajna kombinacja, aby zobaczyć, co autoby to wydedukować.
Jakie są powody istnienia std::decay? W jakich sytuacjach std::decayprzydaje się?
decay_t<decltype(...)>to fajna kombinacja, aby zobaczyć, co autoby to wydedukować.
Odpowiedzi:
<joke> Oczywiście służy do rozkładania std::atomictypów radioaktywnych na nieradioaktywne. </joke>
N2609 to papier, który zaproponował std::decay. Artykuł wyjaśnia:
Mówiąc najprościej,
decay<T>::typeto transformacja typu tożsamości, chyba że T jest typem tablicy lub odniesieniem do typu funkcji. W takich przypadkachdecay<T>::typezwraca odpowiednio wskaźnik lub wskaźnik do funkcji.
Motywującym przykładem jest 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);
}
który zaakceptował jego parametry według wartości, aby literały łańcuchowe działały:
std::pair<std::string, int> p = make_pair("foo", 0);
Jeśli zaakceptuje swoje parametry przez odniesienie, to T1zostanie wydedukowane jako typ tablicy, a następnie zbudowanie a pair<T1, T2>będzie źle sformułowane.
Ale oczywiście prowadzi to do znacznej nieefektywności. Stąd potrzeba decayzastosowania zestawu transformacji, które występują, gdy wystąpi przekazanie przez wartość, co pozwala uzyskać efektywność pobierania parametrów przez odniesienie, ale nadal uzyskać transformacje typu potrzebne do działania kodu z literałami ciągów, typy tablic, typy funkcji i tym podobne:
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));
}
Uwaga: nie jest to rzeczywista make_pairimplementacja C ++ 11 - C ++ 11 make_pairrównież rozpakowuje std::reference_wrappers.
W przypadku funkcji szablonu, które pobierają parametry typu szablonu, często masz parametry uniwersalne. Parametry uniwersalne są prawie zawsze referencjami takiego czy innego rodzaju. Są również wykwalifikowani. W związku z tym większość cech typu nie działa na nich tak, jak można się spodziewać:
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
Rozwiązaniem jest użycie 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";
}
decayjest bardzo agresywny, np. po zastosowaniu do odwołania do tablicy daje wskaźnik. Zazwyczaj jest zbyt agresywny dla tego rodzaju metaprogramowania IMHO.
remove_const_t< remove_reference_t<T> >ewentualnie zawinę w niestandardową metafunkcję.