Std :: decay nedir ve ne zaman kullanılmalıdır?


185

Varlığının nedenleri nelerdir std::decay? Hangi durumlarda std::decayfaydalıdır?


3
Standart kütüphanede, örneğin bir iş parçacığına argümanlar iletilirken kullanılır. Bunların değere göre depolanması gerekir , böylece dizileri depolayamazsınız. Bunun yerine, bir işaretçi saklanır vb. Ayrıca, işlev parametre türü ayarlamalarını taklit eden bir meta işlevdir.
dyp

3
decay_t<decltype(...)>neyin ortaya autoçıkacağını görmek için güzel bir kombinasyon .
Marc Glisse

58
Radyoaktif değişkenler? :)
saiarcot895

7
std :: decay () üç şey yapabilir. 1 T dizisini T * 'ya dönüştürebilir; 2. cv niteleyici ve referans kaldırabilirsiniz; 3. T fonksiyonunu T * 'ye çevirir. örneğin bozunma (boşluk (karakter)) -> boşluk (*) (karakter). Kimse cevaplarda üçüncü kullanımdan bahsetmiyor gibi görünüyor.
r0ng

1
Çok şükür henüz c ++ 'da kuark yok
Wormer

Yanıtlar:


192

<joke> Açıkça radyoaktif std::atomictürleri radyoaktif olmayan türlere bozmak için kullanılır . </joke>

N2609 önerilen makaledirstd::decay . Makale açıklıyor:

Basitçe ifade etmek gerekirse, decay<T>::typeT bir dizi tipi ya da bir fonksiyon tipine referans olması dışında kimlik tipi-dönüşümdür. Bu durumlarda, decay<T>::typebir işleve sırasıyla bir işaretçi veya işaretçi verir.

Motive edici örnek C ++ 03'tür std::make_pair:

template <class T1, class T2> 
inline pair<T1,T2> make_pair(T1 x, T2 y)
{ 
    return pair<T1,T2>(x, y); 
}

dize değişmez değerlerini çalıştırmak için parametrelerini değere göre kabul eden:

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

Eğer parametrelerini referans olarak kabul ederse, o T1zaman bir dizi tipi olarak çıkartılacak ve daha sonra pair<T1, T2>a'nın oluşturulması yanlış oluşturulacaktır.

Ancak bu açıkça önemli verimsizliklere yol açıyor. Bu nedenle, decaypass-by-value meydana geldiğinde oluşan dönüşümler kümesini uygulama gereği , parametreleri referans alarak alma verimliliğini elde etmenizi sağlar, ancak yine de kodunuzun dize değişmezleriyle çalışması için gereken tip dönüşümlerini elde etmenizi sağlar, dizi türleri, işlev türleri ve benzerleri:

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)); 
}

Not: Bu gerçek C ++ 11 make_pairuygulaması değildir - C ++ 11 make_pairde std::reference_wrappers.


"T1 bir dizi tipi olarak çıkartılacak ve daha sonra bir çift <T1, T2> oluşturmak kötü biçimlenecek." buradaki problem nedir?
camino

6
Anlıyorum, bu şekilde sadece 4 karakterli dizeleri kabul edebilen <char [4], int> çifti elde edeceğiz
camino

@camino Anlamıyorum, std :: decay olmadan çiftin ilk kısmının char için bir işaretçi yerine dört karakter için 4 bayt işgal edeceğini mi söylüyorsunuz? Std :: forward bu mu? Bir diziden işaretçiye çürümesini durdurur?
Zebrafish

3
@Zebrafish Dizi bozunmasıdır. Örneğin: şablon <typename T> void f (T &); f ( "abc"); T, char (&) [4] 'dir, ancak şablon <T türü> void f (T); f ( "abc"); T karakteridir *; Burada bir açıklama bulabilirsiniz: stackoverflow.com/questions/7797839/…
camino

69

Bir şablon türündeki parametreleri alan şablon işlevleriyle uğraşırken, genellikle evrensel parametreleriniz olur. Evrensel parametreler hemen hemen her zaman bir veya daha fazla referanstır. Aynı zamanda kalıcı niteliklidir. Bu nedenle, çoğu tür özelliği beklediğiniz gibi çalışmaz:

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

Buradaki çözüm kullanmaktır 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


14
Bundan memnun değilim. decayçok agresiftir, örneğin diziye bir referansa uygulanırsa bir işaretçi verir. Bu tür bir metaprogramlama IMHO'su için genellikle çok agresiftir.
dyp

@dyp, o zaman daha az "saldırgan" olan nedir? Alternatifler nelerdir?
Serge Rogatch

5
@SergeRogatch "Evrensel parametreler" / evrensel referanslar / yönlendirme referansları söz konusu olduğunda, sadece remove_const_t< remove_reference_t<T> >özel bir metafonksiyona sarılırdım.
dyp

1
param nerede kullanılıyor? Bu bir func argümanı ama hiçbir yerde kullanıldığını görmüyorum
savram

2
@savram: Bu kod parçalarında: öyle değil. Değeri değil, yalnızca türü kontrol ediyoruz. Parametrenin adını kaldırırsak daha iyi olmasa bile her şey iyi çalışmalıdır.
Mooing Duck
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.