2014-09-08 1 views
120

В чем причина существования std::decay? В каких ситуациях std::decay полезный?Что такое std :: decay и когда он должен использоваться?

+3

Используется в стандартной библиотеке, например. при передаче аргументов в поток. Они должны быть * сохранены * по значению, поэтому вы не можете хранить, например. массивы. Вместо этого указатель хранится и так далее. Это также metafunction, который имитирует настройки параметров параметров функции. – dyp

+3

'decay_t ' это приятная комбинация, чтобы увидеть, что будет выводить 'auto'. –

+0

[meta.trans.other]: Это поведение похоже на [...= Несколько] конверсии применяется, когда именующее выражение используется в качестве RValue, но и полоски CV-классификаторы из типов классов ** для того, чтобы более близко моделировать по значению аргумента, проходящего **.» – dyp

ответ

116

< анекдот > Он, очевидно, используется для распада радиоактивных std::atomic в нерадиоактивные. </шутка >

N2609 является документ, который предложил std::decay. Бумага объясняет:

Проще говоря, decay<T>::type тождественное преобразование типа, за исключением если Т тип массива или ссылку на тип функции. В случаях 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)); 
} 

Примечание: это не фактическое 11 make_pair C++ реализация - С ++ 11 make_pair также разворачивает std::reference_wrapper с.

+0

несколько связано с распадом на указатель массивов в C. – Alex

+0

«T1 будет выведен как тип массива, а затем построение пары будет плохо сформировано». в чем проблема? – camino

+3

Получаю, таким образом мы получим пару , которая может принимать только строки с 4 символами – camino

43

При работе с функциями шаблона, которые принимают параметры типа шаблона, вы часто имеете универсальные параметры. Универсальные параметры почти всегда являются ссылками того или иного типа. Они также обладают непреодолимой силой. Таким образом, большинство признаков типа не работают на них, как и следовало ожидать:

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

+12

Я недоволен этим. 'decay' очень агрессивен, например, если применяется к ссылке на массив, это дает указатель. Обычно это слишком агрессивно для такого метапрограммирования IMHO. – dyp

+0

@dyp, что менее агрессивно? Что такое альтернативы? –

+2

@SergeRogatch В случае ссылок «универсальные параметры»/универсальных ссылок/пересылки я просто «remove_const_t >», возможно, завернутый в пользовательский метафунг. – dyp