2011-03-20 11 views
7

उदाहरण के लिए:मैं सी ++ में विधि सूचक के पते को कैसे मुद्रित करूं?

struct A { void m() { } }; 

void stream_print() { 
    void(A::*p)(void) = &A::m; 
    std::cerr << p << std::endl; 
} 

void printf_print() { 
    void(A::*p)(void) = &A::m; 
    fprintf(stderr, "%p", p); 
} 

stream_print() फ़ंक्शन हमेशा प्रिंट "1", जो स्पष्ट रूप से नहीं है कि मैं क्या चाहता हूँ। Printf_print संकलित नहीं करता है क्योंकि पी को शून्य * पर नहीं डाला जा सकता है।

मुझे जो चाहिए वह एक विधि सूचक के लिए एक अद्वितीय पहचानकर्ता है जिसे मैं एक कंटेनर में स्टोर कर सकता हूं। मुझे पता है कि यह एक बुरा विचार की तरह लगता है, लेकिन मैं यूनिट परीक्षण के लिए एक छोटा खिलौना विकसित कर रहा हूं जो इससे लाभ उठा सकता है। मैं विधि के अधिभार के बारे में चिंतित नहीं हूं, मुझे पता है कि पॉइंटर को एक विशिष्ट अधिभार में कैसे प्राप्त किया जाए।

मैं सी ++ 0x सक्षम के साथ जी ++ 4.4.3 का उपयोग कर रहा हूं।

यदि आपको कोई संदेह है तो मुझे बताएं।

उत्तर

9

सदस्य फ़ंक्शन पॉइंटर आमतौर पर गैर-तुच्छ आंतरिक संरचना वाला ऑब्जेक्ट होता है। यही कारण है कि आप प्राचीन प्रकार के मुद्रण के लिए इच्छित टूल का उपयोग करके इसे प्रिंट नहीं कर सकते हैं। पॉइंटर को void * पर कास्ट करना एक व्यवहार्य दृष्टिकोण नहीं है, क्योंकि सदस्य सूचक का आकार आम तौर पर sizeof(void *) से बड़ा होता है। इसे void * पर मजबूती से कास्टिंग किसी भी मामले में सूचक प्रतिनिधित्व के एक हिस्से को त्याग देगा, इस प्रकार विशिष्टता की गारंटी नहीं देगी।

यदि आप जो खोज रहे हैं वह पॉइंटर से उत्पन्न एक अनूठी स्ट्रिंग है, तो आप पॉइंटर को एक वर्ण सरणी के रूप में दोबारा परिभाषित कर सकते हैं, और पहचानकर्ता में वर्ण मानों की स्ट्रिंग प्रस्तुति का उपयोग कर सकते हैं। जैसे

void (A::*p)(void) = &A::m; 

for (size_t i = 0; i < sizeof p; ++i) 
    printf("%d ", reinterpret_cast<char *>(&p)[i]); 

printf("\n"); 
+0

+1 जब तक कोई कोई दोष न हो ... –

+0

@Maththieu एम .: सबसे पहले, यह सादा गलत है। सी फ़ंक्शन पॉइंटर्स के रूपांतरण को 'शून्य *' में परिभाषित नहीं करता है और, ज़ाहिर है, इसके बारे में कोई गारंटी नहीं है। सी डेटा पॉइंटर्स और फ़ंक्शन पॉइंटर्स के बीच "मिश्रित" रूपांतरण परिभाषित नहीं करता है। आप एक सामान्य फ़ंक्शन पॉइंटर के रूप में 'शून्य (*) (शून्य)' का उपयोग कर सकते हैं, लेकिन 'शून्य * नहीं। – AnT

+0

@ मैथ्यूयू एम .: दूसरा, प्रश्न सदस्य फ़ंक्शन पॉइंटर्स के बारे में है, न कि स्टैंडअलोन फ़ंक्शंस के पॉइंटर्स के बारे में, जो पूरी तरह से एक अलग कहानी है। – AnT

0

ऐसा करने के लिए कोई पोर्टेबल तरीका नहीं है। लेकिन क्या आपने reinterpret_cast<void*>(p) की कोशिश की है?

मुझे संदेह है कि stream_printstd::operator<<(std::ostream&, bool) का उपयोग कर रहा है, क्योंकि यह सूचक-से-सदस्य प्रकार के लिए एकमात्र वैध रूपांतरण है। यह समझाएगा कि आपको 1 क्यों मिलता है।

मैं काम करने के लिए printf_print की अपेक्षा नहीं करता, भले ही एक कंपाइलर ... के माध्यम से पॉइंटर-टू-सदस्य-फ़ंक्शन पास करने की अनुमति देता हो। sizeof(p) == sizeof(void*) की कोई गारंटी नहीं है, जो अक्सर va_arg से "अपेक्षित" गैर मानक परिणामों के लिए व्यावहारिक न्यूनतम है।

4

कुछ हालांकि मैं नहीं हूँ 100% यकीन है कि मैं सवाल सही ढंग से समझ, अगर कुछ अद्वितीय आईडी पर एक सदस्य सूचक से कुछ मानचित्रण की जरूरत है, निम्नलिखित कोड उद्देश्य को पूरा कर सकता है:

struct A { 
    void f() {} 
    void g(int) {} 
}; 

template< class T, T > 
char* get_unique_id() { 
    static char dummy; 
    return &dummy; 
} 

int main() { 
    set< char* > s; 
    s.insert(get_unique_id< decltype(&A::f), &A::f >()); 
    s.insert(get_unique_id< decltype(&A::g), &A::g >()); 
    s.insert(get_unique_id< decltype(&A::f), &A::f >()); 
    s.insert(get_unique_id< decltype(&A::g), &A::g >()); 
    cout<< s.size() <<endl; // prints 2 
} 

get_unique_id का कॉल थोड़ा लंबा है ...
संभवतः कुछ मैक्रो इसे आसान बनाने में मदद कर सकते हैं।

आशा इस

+0

यहां टेम्पलेट तर्क कटौती के साथ कुछ किया जाना है। हालांकि अच्छा विचार है। –

+0

@AlexandreC .: धन्यवाद! ** कुछ करने के लिए ** है - हाँ, संभवतः 'constexpr'? ईमानदारी से, मैं 0x से इतना परिचित नहीं हूँ। –

+0

को पूरी तरह से आवश्यकता नहीं है: 'टेम्पलेट <टाइपनाम पीएमएफ> char * get_unique_id (पीएमएफ pmf) {स्थिर चार डमी; वापसी &dummy;} '...' s.insert (get_unique_id (&A::f);} 'किसी भी प्रकार के लिए काम करता है, न केवल सदस्य कार्यों के लिए संकेतक। लेकिन आप' std :: type_info' – MSalters

1

में मदद करता है यह केवल जीसीसी के साथ काम करने की जरूरत है, तो आप सदस्य कार्य करने के लिए एक सूचक से एक समारोह सूचक को निकालने के लिए this एक्सटेंशन का उपयोग कर सकते हैं। -Wno-pmf-conversions साथ

#include <iostream> 
#include <stdio.h> 

struct A { void m() { } }; 

typedef void (*mptr)(A*); 

int main() 
{ 
    mptr p = (mptr)(&A::m); 
    std::cerr << (void*)p << std::endl; 
    fprintf(stderr, "%p\n", p); 
} 

संकलित चेतावनी को दबाने के लिए:

यहाँ एक उदाहरण है।

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