Std :: क्षय क्या है और इसका उपयोग कब किया जाना चाहिए?


185

के अस्तित्व के कारण क्या हैं std::decay? किन स्थितियों में std::decayउपयोगी है?


3
इसका उपयोग मानक पुस्तकालय में किया जाता है, उदाहरण के लिए जब एक थ्रेड को तर्क दिया जाता है। जिन्हें मूल्य द्वारा संग्रहीत किया जाना आवश्यक है , इसलिए आप उदाहरणों को संग्रहीत नहीं कर सकते। इसके बजाय, एक सूचक संग्रहीत किया जाता है और इसी तरह। यह एक मेटाफ़ंक्शन भी है जो फ़ंक्शन पैरामीटर प्रकार समायोजन की नकल करता है।
dyp

3
decay_t<decltype(...)>एक अच्छा संयोजन है, यह देखने के लिए कि क्या कम autoहोगा।
मार्क ग्लिससे

58
रेडियोधर्मी चर? :)
saiarcot895

7
std :: क्षय () तीन काम कर सकते हैं। 1 यह T से T * की एक सरणी बदलने में सक्षम है; 2. यह cv क्वालिफायर और संदर्भ को हटा सकता है; 3. यह फ़ंक्शन टी को टी * में परिवर्तित करता है। उदा क्षय (शून्य (चार)) -> शून्य (*) (चार)। लगता है किसी ने जवाब में तीसरे उपयोग का उल्लेख नहीं किया।
r0ng

1
धन्यवाद अच्छा है कि हमारे पास c ++ में क्वार्क अभी तक नहीं है
Wormer

जवाबों:


192

<मजाक> यह स्पष्ट रूप से 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)); 
}

नोट: यह वास्तविक C ++ 11 make_pairकार्यान्वयन नहीं है - C ++ 11 make_pairभी अलिखित है std::reference_wrapper


"T1 को एक सरणी प्रकार के रूप में घटाया जाएगा, और फिर एक जोड़ी का निर्माण <T1, T2> बीमार किया जाएगा।" यहां क्या समस्या है?
कैमिनो

6
मैं इसे प्राप्त करता हूं, इस तरह से हमें जोड़ी मिल जाएगी <char [4], int> जो केवल 4 वर्णों के साथ तार को स्वीकार कर सकती है
कैमिनो

@camino मुझे नहीं मिला, क्या आप कह रहे हैं कि बिना std :: क्षय के पहले भाग में चार बाइट्स के लिए चार बाइट्स के बजाय चार पॉइंटर के लिए एक पॉइंटर चार के लिए होगा? यह है कि क्या एसटी :: आगे करता है? यह एक सरणी से एक सूचक को क्षय से रोकता है?
Zebrafish

3
@Zebrafish यह सरणी क्षय है। उदाहरण के लिए: टेम्पलेट <टाइपनेम टी> शून्य एफ (टी एंड); च ( "abc"); टी चार (&) [4] है, लेकिन टेम्पलेट <टाइपनेम टी> शून्य एफ (टी); च ( "abc"); T चार है *; आप यहां एक स्पष्टीकरण भी पा सकते हैं: stackoverflow.com/questions/7797839/…
कैमिनो

68

टेम्पलेट प्रकार के मापदंडों को लेने वाले टेम्पलेट फ़ंक्शंस से निपटने के दौरान, आपके पास अक्सर सार्वभौमिक पैरामीटर होते हैं। सार्वभौमिक पैरामीटर लगभग हमेशा एक प्रकार या किसी अन्य के संदर्भ होते हैं। वे कांस्टेबल-वाष्पशील भी हैं। जैसे कि, अधिकांश प्रकार के लक्षण उन पर काम नहीं करते हैं जैसा कि आप अपेक्षा करते हैं:

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


14
मैं इससे खुश नहीं हूं। decayबहुत आक्रामक है, उदाहरण के लिए अगर यह एक पॉइंटर की पैदावार के संदर्भ में लागू होता है। यह आमतौर पर इस तरह के मेटाप्रोग्रामिंग IMHO के लिए बहुत आक्रामक है।
dip

@dyp, फिर "कम आक्रामक" क्या है? विकल्प क्या हैं?
सर्ज रोजैच

5
@SergeRogatch "सार्वभौमिक पैरामीटर" / सार्वभौमिक संदर्भ / अग्रेषण संदर्भ के मामले में, मैं बस remove_const_t< remove_reference_t<T> >, संभवत: एक कस्टम परिवर्तन में लिपटे हुए हूं।
dp

1
परम का उपयोग कहां किया जा रहा है? यह
दुर्गंध

2
@ शिवराम: कोड के इन टुकड़ों में: यह नहीं है। हम केवल प्रकार की जाँच कर रहे हैं, मूल्य की नहीं। यदि हमने पैरामीटर का नाम हटा दिया है तो सब कुछ ठीक नहीं होना चाहिए।
मूविंग डक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.