6

मैं इस नमूना कोड मिल गया है के साथ काम करता है:सी ++ सूचक करने वाली विधि टेम्पलेट कटौती संकलन नहीं है, लेकिन 64

struct A 
{ 
    int foo() { return 27; } 
}; 

template<typename T> 
struct Gobstopper 
{ 
}; 

template<> 
struct Gobstopper<int(void)> 
{ 
    Gobstopper(int, int) { } // To differentiate from general Gobstopper template 
}; 

template<typename ClassType, typename Signature> 
void DeduceMethodSignature(Signature ClassType::* method, ClassType& instance) 
{ 
    // If Signature is int(), Gobstopper<> should resolve to the specialized one. 
    // But it only does on x64! 
    Gobstopper<Signature>(1, 2); 
} 

int main(int argc, char** argv) 
{ 
    A a; 
    DeduceMethodSignature(&A::foo, a); 

    return 0; 
} 

यह g++ के साथ ठीक संकलित करता है। यह वीसी 10 के साथ भी ठीक है, लेकिन केवल 64-बिट प्लेटफॉर्म के लिए निर्माण करते समय। जब मैं 32-बिट प्लेटफॉर्म के लिए निर्माण, मैं इस संकलन त्रुटि मिलती है:

error C2661: 'Gobstopper<T>::Gobstopper' : no overloaded function takes 2 arguments 
1>   with 
1>   [ 
1>    T=int (void) 
1>   ] 
1>   c:\...\test.cpp(26) : see reference to function template instantiation 'void DeduceMethodSignature<A,int(void)>(Signature (__thiscall A::*),ClassType &)' being compiled 
1>   with 
1>   [ 
1>    Signature=int (void), 
1>    ClassType=A 
1>   ] 

त्रुटि इंगित करता है कि Gobstopper के गैर विशेष संस्करण का उपयोग किया जा रहा है, जिसका मतलब चाहिए Signature कि int (void) अलावा कुछ है। लेकिन त्रुटि यह भी स्पष्ट रूप से कहती है कि Signatureint (void) है। तो त्रुटि कहां से आती है? और मैं इसे कैसे ठीक कर सकता हूं?

एकमात्र चीज जिसे मैं सोच सकता हूं कि 32-बिट से 64-बिट में बदल सकता है और त्रुटि संदेश में प्रदर्शित हस्ताक्षर में दिखाई नहीं दे रहा है; जाहिर है, there is a unified calling convention for VC x64, whereas for x86 each calling convention is distinct। लेकिन अगर यह समस्या है, तो मुझे नहीं पता कि इसे कैसे ठीक किया जाए।

सहायता!

संपादित करें: मुझे यह उल्लेख करना चाहिए कि मैंने नियमित (गैर-सदस्य) फ़ंक्शन पॉइंटर्स के साथ यह कोशिश की, और यह ठीक काम किया।

उत्तर

5

आप काफी सही हैं। Win32 लक्ष्य के साथ Signature का प्रकार int __thiscall(void) है जबकि x64 पर यह int __cdecl(void) है। ध्यान दें कि या तो लक्ष्य पर गैर-सदस्य फ़ंक्शंस के प्रकार को आमतौर पर int(void) कहा जाता है, वास्तव में int __cdecl(void) है, इसलिए संयोग से वास्तव में निर्मित प्रकारों में से एक (वास्तव में सही नहीं है!) मैचों में।

आम तौर पर टेम्पलेट जादू द्वारा विभिन्न प्रकार के फ़ंक्शन पॉइंटर्स को मिश्रित करने की सलाह नहीं दी जाती है, इसलिए गोबस्टॉपर्स विशेषज्ञता को int (ClassType::*)() जैसे कुछ देखना चाहिए।

+0

हम्म। मेरे संदेह की पुष्टि करने के लिए धन्यवाद (जिस तरह से आपने जांच की थी? मुझे टेम्पलेट तर्कों को डीबग करने में काफी मुश्किल लग रही है)। क्या कोई तरीका है कि मैं कॉलिंग सम्मेलन को 'हस्ताक्षर' से अलग कर सकता हूं? मैं वास्तव में टेम्पलेट विशेषज्ञों को असंबद्ध करने के साधन के रूप में, फ़ंक्शन पॉइंटर को परिभाषित करने के लिए गोबस्टॉपर के भीतर 'टी' का उपयोग नहीं करता हूं। इसके अलावा, nitpick (ठीक है, nitpick) करने के लिए नहीं, लेकिन x64 '__thiscall' पर कॉलिंग सम्मेलन भी नहीं है, लेकिन यह' __cdecl' के साथ संगत होने वाला होता है? – Cameron

+0

वास्तव में, वीसी ++ के लिए 32 बिट सम्मेलन "सामान्य" कार्यों के लिए cdecl है और सदस्य कार्यों के लिए यह है। 64 बिट विंडोज़ पर, यह न तो सीडीसीएल है और न ही 32 बिट पर्यावरण से जाना जाता है, लेकिन कुछ प्रकार के लिए इस तरह की तुलना में कुछ और रजिस्टरों का उपयोग करने में कुछ अलग है। यदि आप और जानना चाहते हैं, तो http://www.agner.org/optimize/calling_conventions.pdf परामर्श पर विचार करें जहां उपयोग में हर कॉलिंग सम्मेलन सूचीबद्ध है। –

+0

ओह, और वीएस पर आप एक प्रकार का नाम देने के लिए 'टाइपिड (टी) .name()' का उपयोग कर सकते हैं - भले ही यह टेम्पलेट तर्क हो। –