Каковы причины существования std::decay
? В каких ситуациях std::decay
пригодится?
c++
c++11
standard-library
Эрик Хавьер Эрнандес Саура
источник
источник
decay_t<decltype(...)>
хорошая комбинация, чтобы увидеть, чтоauto
можно сделать.Ответы:
<joke> Очевидно, он используется для распада радиоактивных
std::atomic
типов на нерадиоактивные. </joke>N2609 - это предложенная бумага
std::decay
. В документе объясняется:В качестве мотивирующего примера можно привести 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 ++ 11make_pair
также разворачиваетstd::reference_wrapper
s.источник
Имея дело с шаблонными функциями, которые принимают параметры типа шаблона, у вас часто есть универсальные параметры. Универсальные параметры почти всегда являются ссылками того или иного рода. Они также квалифицированы как const-volatile. Таким образом, большинство свойств типов работают с ними не так, как вы ожидали:
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"; }
http://coliru.stacked-crooked.com/a/8cbd0119a28a18bd
источник
decay
очень агрессивен, например, если применяется к ссылке на массив, он дает указатель. ИМХО, как правило, это слишком агрессивно для такого рода метапрограммирования.remove_const_t< remove_reference_t<T> >
, возможно, обернул пользовательскую метафункцию.int
,const int
,int&
,const int&
,int&&
,const int&&
,volatile int
,volatile int&
,volatile int&&
, и т.д., все разные.