2010-05-20 25 views
6

अद्यतन: कुछ अतिरिक्त पढ़ने के बाद, जो मैं वास्तव में चाहता था उसे प्रारंभिक बाध्यकारी (जिसे गैर वर्चुअल फ़ंक्शंस और गैर-पीआईसी कोड के लिए तत्काल कॉल में अनुवादित किया जाना चाहिए) की गारंटी दी गई थी, जिसे एक (सदस्य) फ़ंक्शन पास करके किया जा सकता है एक टेम्पलेट पैरामीटर के रूप में। मेरी समस्या यह थी कि जीसीसी < 4.5 और आईसीसी 11.1 सदस्य फ़ंक्शन पॉइंटर टेम्पलेट पैरामीटर कॉल के लिए कुछ फंकी निर्देश उत्पन्न कर सकता है। AFAICT, gcc> = 4,5 और बनाम 2008 इन टेम्पलेट पैरामीटर को ठीक से कॉल करते हैं।सी ++ में फ़ंक्शन पता अक्षर कहाँ हैं?

सबसे पहले, शायद शाब्दिक इस अवधारणा के लिए सही शब्द नहीं है, लेकिन अपने निकटतम मैं (प्रथम श्रेणी के नागरिक के रूप में कार्य के अर्थ में नहीं शाब्दिक) के बारे में सोच सकता है।

callq <immediate address> 

लेकिन अगर आप एक समारोह कॉल एक समारोह सूचक का उपयोग कर, यह कुछ इस तरह करने के लिए संकलित:

विचार है कि जब आप एक पारंपरिक समारोह कॉल करते हैं, यह कुछ इस तरह करने के लिए संकलित है

mov <memory location>,%rax 
callq *%rax 

जो सब ठीक है और अच्छा है। हालांकि, अगर मैं एक टेम्पलेट लाइब्रेरी लिख रहा हूं जिसके लिए निर्दिष्ट तर्क सूची के साथ किसी प्रकार की कॉलबैक की आवश्यकता है और लाइब्रेरी के उपयोगकर्ता को यह जानने की उम्मीद है कि वे संकलित समय पर किस फ़ंक्शन को कॉल करना चाहते हैं? फिर मैं टेम्पलेट पैरामीटर के रूप में फ़ंक्शन शाब्दिक को स्वीकार करने के लिए अपना टेम्पलेट लिखना चाहता हूं। तो, समान

को
template <int int_literal> 
struct my_template {...};` 

मैं

template <func_literal_t func_literal> 
struct my_template {...}; 

लिखने और my_template भीतर func_literal callq <immediate address> को संकलित करने के लिए कॉल करना चाहते हैं।

क्या इसके लिए सी ++ में कोई सुविधा है, या एक ही प्रभाव प्राप्त करने के लिए आसपास एक काम है? यदि नहीं, तो क्यों नहीं (उदा। कुछ cataclysmic साइड इफेक्ट्स)? सी ++ 0x या दूसरी भाषा के बारे में कैसे?

+0

यह विषय उपयोगी है, क्योंकि यह रन-टाइम के दौरान विभिन्न कार्यक्षमताओं को स्वैप करने की अनुमति देता है। उदाहरण के लिए, डॉस एपीआई कार्यों को मैप करने के लिए आईडी का उपयोग करता है। यह डीओएस कार्यक्षमता को कम से कम निष्पादन योग्य को प्रभावित करने की अनुमति देता है। लुकअप टेबल में बस सामग्री (फ़ंक्शन पते) को बदलें। –

+0

टेम्पलेट्स के साथ संयोजन में फ़ंक्शंस संकलित-समय हैं। अधिकांश एसटीएल इस तरह काम करते हैं या आपकी समस्या में कोई चेतावनी है? – pmr

+0

@pmr चेतावनी यह है कि समाधान उपयोगकर्ताओं के कोड पर कोई प्रभाव नहीं होना चाहिए; अगर वे फ़ंक्शन ऑब्जेक्ट्स का उपयोग नहीं कर रहे हैं, तो मैं उन्हें फ़ंक्शन ऑब्जेक्ट्स का उपयोग करने के लिए मजबूर नहीं करना चाहता हूं। – academicRobot

उत्तर

3

यदि आप अपने टेम्पलेट में फ़ंक्शन पॉइंटर प्रकार का उपयोग करते हैं और इसे एक निश्चित फ़ंक्शन के साथ तुरंत चालू करते हैं, तो संकलक को उस फ़ंक्शन पॉइंटर कॉल के लिए प्रत्यक्ष कॉल का उपयोग करना चाहिए।

+0

+1 बस इसे आज़माएं, बहुत अच्छा काम करता है। मनमानी वर्ग से सदस्य कार्यों को स्वीकार करने के बारे में क्या (आभासी कार्यों पर विचार नहीं)? आपका जवाब मुझे इसके लिए कुछ विचार देता है ... – academicRobot

1

CodeProject.com:

मैं कई प्लेटफार्मों पर उपयोग किया है: http://www.codeproject.com/kb/cpp/FastDelegate.aspx

खोज परिणामों में देखा, पढ़ा जाएगा: ... http://www.codeproject.com/KB/cpp/ImpossiblyFastCppDelegate.aspx

या बात की तरह यह नहीं है आप खोज रहे हैं?

+0

पहला लिंक अभी भी पॉइंटर कॉल का उपयोग करता है, सोचा कि वे सदस्य फ़ंक्शन कॉल से तेज़ हैं।दूसरे के बारे में पता नहीं था, इसमें देखेंगे ... – academicRobot

+0

इससे पहले कि आप उस दूसरे लिंक को पढ़ने का इरादा नहीं रखते थे। मैंने इसके साथ एक मिनट पहले खेला और कोई पासा नहीं। असल में, यह थोड़ा अजीब है। एक आंतरिक संरचना है जो कॉल जुर्माना (तत्काल मोड में) एम्बेड करती है, लेकिन इसे स्वयं फ़ंक्शन पॉइंटर के माध्यम से बुलाया जाता है। सोचें कि प्रतिनिधियों के बीच इंटरऑप प्राप्त करना आवश्यक है, जो यहां एक आवश्यकता नहीं है। – academicRobot

0

सी ++ भाषा में, अनुवादक निष्पादन योग्य में फ़ंक्शन नामों को फोल्ड नहीं करते हैं, वे खो जाते हैं और हमेशा के लिए चले जाते हैं।

आप फ़ंक्शन नाम बनाम फ़ंक्शन पता बना सकते हैं। चूंकि सी और सी ++ स्टिकर के प्रकार की जानकारी के लिए हैं, इसलिए असेंबली भाषा में इसे आसानी से घोषित किया जा सकता है। उच्च स्तर की भाषा में, आपको प्रत्येक अलग-अलग प्रकार के फ़ंक्शन पॉइंटर के लिए एक टेबल रखना होगा। हालांकि, असेंबली में, यह परवाह नहीं है। यद्यपि आप एक फ़ंक्शन पॉइंटर वापस करने या फ़ंक्शन निष्पादित करने के लिए switch के साथ फ़ंक्शन का उपयोग कर सकते हैं।

एक विकल्प फ़ंक्शन पते बनाम फ़ंक्शन आईडी (एनम्स) है।

+0

मैं रन टाइम पर फ़ंक्शन नाम का उपयोग नहीं करना चाहता, मैं * संकलन समय * पर फ़ंक्शन नाम के लिए एक सरोगेट का उपयोग करना चाहता हूं। आप प्रस्तावित समाधान अभी भी रन टाइम पर फ़ंक्शन पॉइंटर्स का उपयोग कर रहे हैं। जब तक मैं गलत समझ नहीं पाता, कृपया यह बताएं कि क्या यह मामला है। – academicRobot

0

कम से कम अगर मैं आपके सवाल का सही ढंग से समझ, यह मामूली बात है:

template <class func> 
struct whatever { 
    operator()() { 
     func(); 
    } 
}; 

func(); करने के लिए कॉल सामान्य रूप से func() के लिए एक सीधा फोन के रूप में खत्म हो जाएगा के रूप में आपके द्वारा पूछे गए हैं, या अगर func() छोटा है, इसका कोड अक्सर इनलाइन उत्पन्न किया जाएगा। यदि आप इनलाइन उत्पन्न होने की संभावनाओं में सुधार करना चाहते हैं, तो आप आम तौर पर एक सामान्य फ़ंक्शन के बजाय इसे एक मजेदार (वर्ग जो operator() ओवरलोड करता है) के रूप में लिखना चाहते हैं। एक सामान्य कार्य के रूप में, आप अक्सर वास्तविक फ़ंक्शन को कॉल करना समाप्त कर देंगे (लेकिन यह एक प्रत्यक्ष कॉल होगा, पॉइंटर के माध्यम से कॉल नहीं)।

संपादित करें: मुझे यकीन नहीं है कि मैं क्या सोच रहा था, लेकिन आप बिल्कुल सही हैं: यह केवल एक मजेदार के साथ काम करेगा, वास्तविक कार्य नहीं। मैं क्षमाप्रार्थी हूं।

+0

एक मजेदार के साथ महान काम करता है। लेकिन एक समारोह के लिए संकलन नहीं: पूर्णांक मुख्य (शून्य) पूर्णांक गूंज (int i) {वापसी मैं} {जो कुछ whateverObj, 1 वापसी;} देता है "त्रुटि: उम्मीद एक प्रकार, मिल गया 'गूंज '' – academicRobot

+0

यह मेरी पहली चीजों में से एक था, इसलिए आपको मुझसे कोई आलोचना नहीं मिलेगी :) – academicRobot

+0

यह सही समाधान है। 'Std :: कम ' देखें, जो ठीक उसी पैटर्न का उपयोग करता है, और इसी कारण से। प्रत्यक्ष कॉल यह है कि क्यों 'std :: sort' 'std :: qsort' धड़कता है। – MSalters

1
#include <iostream>                

template<void F()>                
struct CALLER                 
{                    
    static void do_call()               
    {                    
    std::cout << __PRETTY_FUNCTION__ << std::endl;        
    F();                   
    };                    
};                    

void f()                   
{                    
    std::cout << __PRETTY_FUNCTION__ << std::endl;         
}                    

int main()                  
{                    
    CALLER<f>::do_call();               
    return(0);                  
}                    
0

सोचा मैं मानक काम करता है, अन्य उत्तर यहाँ से बढ़ाया के लिए अपने खुद के समाधान का हिस्सा चाहते हैं। यह एक छोटे हाथ के रूप में variadic paramters का उपयोग करता है। एन-आरी टेम्पलेट्स के सेट के रूप में ऐसा करने के लिए यह कठिन नहीं होगा (केवल थकाऊ)। दिलचस्प बात यह है कि एन-आरी टेम्पलेट्स इस पैटर्न के लिए अधिक लचीला हैं, क्योंकि नेस्टेड स्ट्रक्चर की आवश्यकता नहीं होगी। g++ -std=c++0x

template <typename F> 
struct caller; 

template <class R, class ... A> 
struct caller<R(A ...)>{ 
    template <R F(A ...)> 
    struct func{ 
     R operator()(A ... args){ 
     return F(args ...); 
     } 
    }; 
}; 

जो लागू करते हैं और इस तरह कहा जाता है के साथ संकलित:

int echoFunc(int i) {std::cout << "echo " << i << std::endl; return i;} 
... 
caller<int(int)>::func<echoFunc> f; 
f(1); 

-O2 बिना f(1) करने के लिए कॉल echoFunc को तत्काल कॉल करने के लिए कम कर देता है, दो नेस्टेड तत्काल कार्यप्रणाली कॉल को संकलित -O2 साथ।

यह सदस्य कार्यों के लिए भी जीसीसी> = 4.5 और बनाम 2008 के साथ अपेक्षित काम करता है।

0

टेम्पलेट के फ़ंक्शन संदर्भ को पास करना भी संभव है। यह नवीनतम क्लैंग (3.2) में संकलित करता है और प्रिंट करता है "हैलो वर्ल्ड!" आपकी अपेक्षानुसार:

template<void(& f)()> struct test { 
    void operator()() { 
     f(); 
    } 
}; 
void foo() { 
    std::cout << "Hello World!\n"; 
} 
test<foo> bar; 
int main() { 
    bar(); 
} 

मुझे यकीन है कि अगर यह वास्तव में एक अंतर एक समारोह सूचक उपयोग की तुलना में, हालांकि बनाती हूँ नहीं हूँ।

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