2014-10-25 16 views
13

हम एक पैरामीटर लग रहा है कि void() तरह void(*)() के रूप में लिखा हो जाएगा जानते हैं। इस सरणी-टू-सूचक क्षय जहां int[]int* हो जाता है के समान है। ऐसे कई मामले हैं जहां एक सरणी का उपयोग करने से यह एक सूचक को क्षीण कर देगा। क्या पैरामीटर के अलावा अन्य मामले हैं जहां "क्षय" कार्य करता है?समारोह करने के लिए समारोह-सूचक "क्षय"

सी ++ मानक कहता है:

§8.3.5/5

... समारोह लौटने प्रत्येक पैरामीटर के प्रकार, प्रकार "टी की सरणी" या "के किसी भी पैरामीटर निर्धारण करने के बाद टी सूचक टी करने के लिए कार्य करने के लिए सूचक क्रमशः लौटने टी, "

के बाद से टिप्पणीकार नीचे me..here क्या मेरी संकलक शो है विश्वास करने के लिए नहीं लगता है" या "..." होने के लिए निकाला जाता है " रों।

void handler(void func()) 
{ 
    func(42); 
} 

main.cpp: In function 'void handler(void (*)())': 
main.cpp:5:12: error: too many arguments to function 
    func(42); 
     ^
+0

पहला बिट गलत है –

+0

@Ed देखभाल की व्याख्या करने के लिए? – user4179986

+0

इस प्रश्न का उद्देश्य क्या है –

उत्तर

-1

हाँ वे दोनों पॉइंटर्स हैं, पहला फ़ंक्शन पॉइंटर है, दूसरा स्याही के ब्लॉक के लिए एक सूचक है। * एक बिंदु की तरह दिखता है।

0

अरै, और फ़ंक्शन के बीच एक और स्पष्ट समानता निम्नलिखित होगा:

void bar(string message) 
{ 
    cout << message << endl; 
} 

void main() 
{ 
    int myArray[10]; 
    int* p = myArray; //array to pointer to array 

    void (*f)(string); 
    f = bar; //function to function pointer decay 
} 
4

जब यह डेटा प्रकार के बारे में है, कार्यों सी और सी में प्रथम श्रेणी के नागरिकों ++ (प्रश्न के बारे में है नहीं कर रहे हैं सी ++ लेकिन व्यवहार विरासत में मिलती है सी से)। वे कोड हैं, डेटा नहीं हैं और उन्हें कॉपी नहीं किया जा सकता है, कार्यों के लिए तर्क के रूप में पारित किया जा सकता है या कार्यों द्वारा लौटाया जा सकता है (लेकिन ये सभी फ़ंक्शंस के लिए पॉइंटर्स के साथ हो सकते हैं।)

यही कारण है कि फ़ंक्शन नाम को पॉइंटर की तरह माना जाता है समारोह और समारोह शरीर की तरह नहीं।

कार्य करने के लिए एक सूचक के बजाय एक समारोह (नाम) का उपयोग करने के संभावना सिर्फ एक शिष्टाचार भाषा प्रोग्रामर करने के लिए बनाता है, और नहीं एक "क्षय" है।

सरणियों के लिए एक ही: वे कॉपी नहीं किए जाते, समारोह तर्क के रूप में नहीं पारित कर दिया और कार्यों से नहीं लौटे। अपनी पहली तत्व का पता बजाय प्रयोग किया जाता है (कॉपी, समारोह तर्क के रूप में पारित कर दिया या कार्यों द्वारा दिया)। यही कारण है कि सरणी नाम अपने पहले तत्व और फिर से पते के बजाय इस्तेमाल किया जा सकता, यह सिर्फ एक तरह से कम (और कम सुलझा) कोड लिखने के लिए है।

कंपाइलर के लिए, एक फ़ंक्शन मेमोरी का एक ब्लॉक होता है (जिसमें कोड को कुछ समय पर निष्पादित किया जाता है) जो स्थानांतरित नहीं होता है और इसके पते से पहचानता है, यानी फ़ंक्शन पर सूचक। एक सरणी डेटा का एक ब्लॉक भी है जो स्थानांतरित नहीं होता है और इसकी पहचान (जिसे इसके पहले तत्व का पता भी है) द्वारा पहचाना जाता है। फिर, यह एक सूचक है।

उच्च स्तर (सी, सी ++) पर और array की अवधारणाओं को संकलक द्वारा आदिम मूल्यों (पॉइंटर्स) में अनुवाद किया जाता है जो निम्न स्तर (असेंबलर, मशीन कोड) द्वारा समझा जाता है।

9

तीन रूपांतरण हैं जिन्हें लैवल्यू ट्रांसफॉर्मेशन माना जाता है: लवल्यू-टू-रावल्यू, सरणी-टू-पॉइंटर, और फ़ंक्शन-टू-पॉइंटर। आप इस "क्षय" को कॉल कर सकते हैं क्योंकि std::decay इन प्रकारों से करेगा, लेकिन मानक सिर्फ यह एक फ़ंक्शन-टू-पॉइंटर रूपांतरण [रूपांतरण।समारोह]:

समारोह प्रकार T का एक lvalue प्रकार का एक prvalue में बदला जा सकता परिणाम कार्य करने के लिए एक सूचक है "T सूचक।"।

यदि आप पूछ रहे हैं कि फ़ंक्शन-टू-पॉइंटर रूपांतरण कब होता है, तो वे मूल रूप से वही होते हैं जब अन्य दो लालू परिवर्तन होते हैं।

एक संकार्य के रूप में एक समारोह का उपयोग करना, [expr]/9:

हम सिर्फ क्रम में मानक के माध्यम से जाना है, तो निम्न मामलों की एक विस्तृत सूची जहां समारोह करने के लिए सूचक रूपांतरण होता है जब भी एक ग्लैवल्यू अभिव्यक्ति ऑपरेटर के एक ऑपरेंड के रूप में दिखाई देती है जो उस ऑपरेंड के लिए एक अनुमान की अपेक्षा करता है, लेल्यू-टू-रावल्यू (4.1), सरणी-टू-पॉइंटर (4.2), या फ़ंक्शन-टू-पॉइंटर (4.3) मानक रूपांतरण अभिव्यक्ति को एक प्रसार में बदलने के लिए लागू किया गया है।

एक varargs कार्य करने के लिए एक तर्क के रूप में एक समारोह का उपयोग करना, [expr.call]/7:

जब किसी दिए गए तर्क के लिए कोई पैरामीटर नहीं है, तर्क इस तरह से पारित कर दिया है कि प्राप्त करने वाला फ़ंक्शन va_arg (18.10) का आह्वान करके तर्क का मान प्राप्त कर सकता है ... lvalue-to-rvalue (4.1), सरणी-से-पॉइंटर (4.2), और फ़ंक्शन-टू-पॉइंटर (4.3) मानक रूपांतरण हैं तर्क अभिव्यक्ति पर प्रदर्शन किया।

आप कर सकते हैं static_cast दूर इस रूपांतरण, [expr.static.cast]/7:

किसी भी मानक रूपांतरण अनुक्रम (खंड 4) एक lvalue करने वाली rvalue युक्त नहीं की प्रतिलोम (4.1), सरणी- सूचक (4.2), फ़ंक्शन-टू-पॉइंटर (4.3), शून्य सूचक (4.10), शून्य सदस्य सूचक (4.11), या बूलियन (4.12) रूपांतरण, स्पष्ट रूप से static_cast का उपयोग करके किया जा सकता है।

अन्यथा हालांकि, संकार्य आप में पारित परिवर्तित हो जाएगा, [expr.static.cast]/8:

lvalue करने वाली rvalue (4.1), सरणी-टू-सूचक (4.2), और फ़ंक्शन-टू-पॉइंटर (4.3) रूपांतरण ऑपरेटरों को पर लागू होते हैं।

reinterpret_cast का उपयोग करना, [expr.reinterpret.cast]/1:

अभिव्यक्ति reinterpret_cast<T>(v) का परिणाम अभिव्यक्ति v परिवर्तित टाइप करने के लिए T का परिणाम है। यदि T एक लवल्यू संदर्भ प्रकार या फ़ंक्शन प्रकार के लिए एक रावल्यू संदर्भ है, तो परिणाम एक अंतराल है; यदि T ऑब्जेक्ट प्रकार के रैवल्यू संदर्भ है, तो परिणाम एक xvalue है; अन्यथा, परिणाम एक प्रावधान है और lvalue-torvalue (4.1), सरणी-से-पॉइंटर (4.2), और फ़ंक्शन-टू-पॉइंटर (4.3) मानक रूपांतरण अभिव्यक्ति v पर किए जाते हैं।

[expr.const.cast] const_cast का उपयोग करना,, ऊपर करने के लिए मूल रूप से समान शब्दों के साथ। सशर्त ऑपरेटर [expr.cond] का उपयोग करना,:

lvalue करने वाली rvalue (4.1), सरणी-टू-सूचक (4.2), और समारोह करने के लिए सूचक (4.3) मानक रूपांतरण पर प्रदर्शन कर रहे हैं दूसरा और तीसरा ऑपरेंड।

उपरोक्त स्थितियों में से सभी में

सूचना, यह हमेशा lvalue परिवर्तनों के सभी है।

टेम्पलेट्स में फ़ंक्शन-टू-पॉइंटर रूपांतरण भी होते हैं। एक गैर प्रकार पैरामीटर के रूप में एक समारोह पासिंग, [temp.arg.nontype] /5.4:

एक गैर प्रकार के लिए टेम्पलेट पैरामीटर प्रकार सूचक की कार्य करने के लिए, समारोह करने के लिए सूचक रूपांतरण (4.3) [temp.deduct.call]

या प्रकार कटौती लागू किया जाता है,/2:

:

तो P एक संदर्भ प्रकार नहीं है

  • - यदि A एक सरणी प्रकार है, तो सरणी-से-पॉइंटर मानक रूपांतरण (4.2) द्वारा उत्पादित सूचक प्रकार A के स्थान पर कटौती के लिए उपयोग किया जाता है; अन्यथा,
  • - यदि A फ़ंक्शन प्रकार है, तो फ़ंक्शन-टू-पॉइंटर मानक रूपांतरण (4.3) द्वारा उत्पादित पॉइंटर प्रकार का उपयोग A के स्थान पर कटौती के लिए किया जाता है; अन्यथा,

या कनवर्ज़न फ़ंक्शन टेम्पलेट कटौती, लगभग वही शब्द के साथ।

और अंत में, जाहिर है, std::decay ही है, [meta.trans.other], में जोर मेरा परिभाषित:

Uremove_reference_t<T> बनें। यदि is_array<U>::value सत्य है, तो सदस्य टाइपपीफ़ प्रकार remove_extent_t<U>* के बराबर होगा। यदि is_function<U>::value सत्य है, तो सदस्य टाइपपीफ़ प्रकार add_pointer_t<U> के बराबर होगा। अन्यथा सदस्य टाइपपीफ प्रकार remove_cv_t<U> के बराबर है। [नोट: यह व्यवहार lvalue-to-rvalue (4.1), सरणी-से-पॉइंटर (4.2), और फ़ंक्शन-टू-पॉइंटर (4.3) रूपांतरणों के समान होता है जब एक लालू अभिव्यक्ति को रावल्यू के रूप में उपयोग किया जाता है, लेकिन सीवी-वर्ग प्रकारों से क्वालीफायर भी बहस के आधार पर अधिक बारीकी से मॉडल के लिए स्ट्रिप्स। -एंड नोट]

संबंधित मुद्दे