Які причини існування std::decay? У яких ситуаціях std::decayкорисно?
decay_t<decltype(...)>це приємне поєднання, щоб побачити, що autoможе вивести.
Які причини існування std::decay? У яких ситуаціях std::decayкорисно?
decay_t<decltype(...)>це приємне поєднання, щоб побачити, що autoможе вивести.
Відповіді:
<joke> Він, очевидно, використовується для розкладання радіоактивних std::atomicтипів на нерадіоактивні. </joke>
N2609 - це документ, що пропонується std::decay. У статті пояснюється:
Простіше кажучи,
decay<T>::typeце перетворення типу ідентичності, за винятком випадків, коли T - тип масиву або посилання на тип функції. У цих випадкахdecay<T>::typeдається покажчик або покажчик на функцію відповідно.
Мотиваційний приклад: 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);
}
який прийняв його параметри за значенням, щоб змусити літеральні рядки працювати:
std::pair<std::string, int> p = make_pair("foo", 0);
Якщо він прийняв його параметри за посиланням, то T1він буде виведений як тип масиву, а потім побудова а pair<T1, T2>буде неправильно сформована.
Але очевидно, це призводить до значної неефективності. Отже, потрібно decayзастосовувати набір перетворень, що виникає при проходженні значення, що дозволяє вам отримати ефективність прийому параметрів за посиланням, але все ж отримати перетворення типів, необхідні для вашого коду для роботи з рядковими літералами, типи масивів, типи функцій тощо:
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));
}
Примітка: це не реальна реалізація C ++ 11 make_pair- C ++ 11 make_pairтакож розгортається std::reference_wrappers.
У роботі з функціями шаблону, які приймають параметри типу шаблону, у вас часто є універсальні параметри. Універсальні параметри майже завжди є посиланнями того чи іншого виду. Вони також кваліфіковані на постійних умовах. Таким чином, більшість типів рис не працює на них так, як ви очікували:
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
Рішення тут полягає у використанні 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дуже агресивний, наприклад, якщо застосувати до посилання масив, він дає вказівник. Зазвичай це занадто агресивно для такого типу метапрограмування IMHO.
remove_const_t< remove_reference_t<T> >, можливо, загорнутий у власну метафункцію.