2014-09-08 20 views
120

Jakie są powody istnienia std::decay? W jakich sytuacjach przydatne jest std::decay?Co to jest std :: decay i kiedy powinno się go używać?

+3

Jest używany w standardowej bibliotece np. podczas przekazywania argumentów do wątku. Te muszą być * przechowywane *, według wartości, więc nie można przechowywać np. tablice. Zamiast tego zapisywany jest wskaźnik i tak dalej. Jest to także metafunkcja, która naśladuje korekty typu parametru funkcji. – dyp

+3

'decay_t ' jest ładną kombinacją, aby zobaczyć, co 'auto' wydedukuje. –

+0

[meta.trans.other] states: To zachowanie jest podobne do [...= Kilka] konwersje stosowane przy lwartością ekspresja stosowane jako rvalue, ale paski również CV zakwalifikowanych do typów klas ** aby ściślej modelowania przez wartość argumentu przechodzącej ** „. – dyp

Odpowiedz

116

< żart > Jest to oczywiście używane do rozpadu radioaktywnego std::atomic typów do nieradioaktywnych. </żart >

N2609 jest papier, który zaproponował std::decay. Papier wyjaśnia:

Mówiąc najprościej, decay<T>::type jest tożsamość typu transformacja wyjątkiem jeśli T jest typem tablicą lub odwołaniem do rodzaju funkcji. W tych przypadkach , decay<T>::type daje odpowiednio wskaźnik lub wskaźnik do funkcji, .

motywującą 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 przyjął swoje parametry przez wartość, aby literały łańcuchowe działa:

std::pair<std::string, int> p = make_pair("foo", 0); 

Jeśli akceptowane swoje parametry przez odniesienie, następnie T1 zostanie wydedukowane jako typ tablicowy, a następnie skonstruowanie modelu pair<T1, T2> będzie źle sformułowane.

Ale oczywiście prowadzi to do znacznej nieefektywności. Stąd potrzeba decay, aby zastosować zestaw transformacji, który występuje, gdy występuje wartość pass-by-value, co pozwala uzyskać efektywność przyjmowania parametrów przez odniesienie, ale nadal uzyskać transformacje typu potrzebne do pracy kodu z literałami łańcuchowymi , typy macierzy, typy funkcyjne i podobne artykuły:

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: to nie jest rzeczywiste C++ 11 make_pair realizacja - C++ 11 make_pair rozpakowuje również std::reference_wrapper s.

+0

nieco powiązane: zanikiem do wskaźnika tablic w C. – Alex

+0

"T1 zostanie wyprowadzone jako typ tablicowy, a następnie skonstruowanie pary będzie źle sformułowane." Jaki jest tutaj problem? – camino

+3

Rozumiem, w ten sposób otrzymamy parę , która może przyjmować tylko ciągi z 4 znakami – camino

43

W przypadku funkcji szablonu, które pobierają parametry typu szablonu, często mają uniwersalne parametry. Parametry uniwersalne są prawie zawsze referencjami tego samego rodzaju. Są także niezmiennie wykwalifikowani. Jako takie, większość cech typu nie działają na nich, 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 tego problemu 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"; 
} 

http://coliru.stacked-crooked.com/a/8cbd0119a28a18bd

+12

Nie jestem z tego zadowolony. "Zepsucie" jest bardzo agresywne, np. jeśli zastosowane do odniesienia do tablica daje wskaźnik.Zwykle jest zbyt agresywny dla tego rodzaju IMHO metaprogramowania – dyp

+0

@dyp, co jest mniej "agresywne" to? Jakie są alternatywy? –

+2

@SergeRogatch W przypadku "parametrów uniwersalnych"/odniesień uniwersalnych/odniesień do przekazywania, po prostu 'remove_const_t >', ewentualnie zawinięte w niestandardową metafunkcji. – dyp

Powiązane problemy