2013-03-24 19 views
6

मैं एक वर्ग समारोह (व्यवधान सेवा नियमित) का उपयोग करने की कोशिश कर रहा हूँ,कक्षा सदस्य समारोह सूचक

void (ClassName::*fp)(void)=ClassName::FunctionName; 

और एक Arduino के साथ जोड़ते निम्न प्रकार के जानकारी के साथ समारोह का उपयोग कर पिन बीच में, लेकिन वह ऐसा नहीं करता काम।

void attachInterrupt(int, void (*)(void),int); 

मैं यह कैसे कर सकता हूं? इंटरप्ट सेवा दिनचर्या (आईएसआर) को निजी ऑब्जेक्ट डेटा तक पहुंचने की आवश्यकता है, इसलिए मैं कक्षा के बाहर कोई फ़ंक्शन नहीं कर सकता।

मेरे संकलक त्रुटि:

नोट: मैं कक्षा के अंदर एक समाधान के लिए देख रहा हूँ और जवाब यह है कि मुझे एक समाधान से पता चलता है या मुझे पता चलता है कि यह संभव नहीं है स्वीकार करेंगे।

+2

यदि आपको कोई त्रुटि हो रही है। यह क्या त्रुटि है? – 0x499602D2

+0

मैं विजुअल स्टूडियो 2012 कंपाइलर का उपयोग कर रहा हूं। मैं अपने प्रश्न में संकलक त्रुटि डाल दूंगा। –

+0

क्षमा करें, पहले गलत गलती त्रुटि, अब यह सही है –

उत्तर

6

यदि फ़ंक्शन static नहीं है, तो आप इसे किसी फ़ंक्शन में इनपुट में पास नहीं कर सकते जो गैर-सदस्य फ़ंक्शन पॉइंटर स्वीकार करता है।

मान लें कि गैर-static सदस्य फ़ंक्शन के पास पहले पैरामीटर के रूप में ClassName पर एक निहित सूचक है, जो उस ऑब्जेक्ट को इंगित करता है जिस पर सदस्य फ़ंक्शन का आह्वान किया जा रहा है।

struct X 
{ 
    static void foo() { } // Does not have an implicit "this" pointer argument 
    void bar() { } // Has an implicit "this" pointer argument 
}; 

int main() 
{ 
    void (*f)() = &X::foo; // OK: foo is static 
    void (*g)() = &X::bar; // ERROR! bar is non-static 
} 

यहाँ, यहाँ तक कि std::bind() नहीं काम करेंगे, क्योंकि परिणाम एक समारोह सूचक के लिए परिवर्तनीय नहीं है। लैम्ब्डा फ़ंक्शन पॉइंटर्स में परिवर्तनीय होते हैं, लेकिन केवल तभी जब वे गैर-कैप्चरिंग होते हैं (और यहां एक लैम्ब्डा को सदस्य फ़ंक्शन को आमंत्रित करने के लिए ऑब्जेक्ट को कैप्चर करने की आवश्यकता होगी)।

इसलिए, एकमात्र (बदसूरत) कामकाज वैश्विक एडाप्टर फ़ंक्शन होना है जो किसी वैश्विक ऑब्जेक्ट चर के माध्यम से उपलब्ध ऑब्जेक्ट पर सदस्य फ़ंक्शन को आमंत्रित करता है।

struct X 
{ 
    void bar() { } 
}; 

void function_taking_a_function_pointer(void (*f)()) 
{ 
    // Do something... 
    f(); 
} 

X* pX = nullptr; 
void bar_adapter() 
{ 
    pX->bar(); 
} 

int main() 
{ 
    X x; // Some object I want to invoke the member function bar() on... 

    pX = &x; // Set the global pointer and invoke the function... 
    function_taking_a_function_pointer(bar_adapter); 
} 

आप चाहते हैं, तो आप एक समारोह में bar_adapter मोड़ टेम्पलेट, और सूचक-टू-सदस्य-समारोह को पारित करके इस थोड़ा अधिक लचीला बनाने कर सकते हैं: वैश्विक सूचक चर पहले फ़ंक्शन को कॉल करने के लिए सेट कर दिया जाता एक टेम्पलेट तर्क के रूप में:

template<typename T, void (T::*mf)()> 
void adapter() 
{ 
    (pX->*mf)(); 
} 

यहाँ कैसे आप इसका इस्तेमाल होता है: अंत में

#include <iostream> 

struct X 
{ 
    void foo() { std::cout << "X::foo()" << std::endl; } 
    void bar() { std::cout << "X::bar()" << std::endl; } 
}; 

void function_taking_a_function_pointer(void (*f)()) 
{ 
    // Do something... 
    f(); 
} 

X* pX = nullptr; 

template<typename T, void (T::*mf)()> 
void adapter() 
{ 
    (pX->*mf)(); 
} 

int main() 
{ 
    X x; // Some object I want to invoke the member function bar() on... 

    pX = &x; // Set the global pointer and invoke the function(s)... 

    function_taking_a_function_pointer(adapter<X, &X::foo>); 
    function_taking_a_function_pointer(adapter<X, &X::bar>); 
} 

, उसे ई live example है।

+0

धन्यवाद, बहुत ही जानकारीपूर्ण उत्तर। –

+0

@FlyingSwissman: खुशी है कि मैं –

2

प्रत्येक वर्ग सदस्य फ़ंक्शन में एक अंतर्निहित पहला पैरामीटर है जो this पॉइंटर है, इसलिए वास्तव में आपकी विधि शून्य पैरामीटर सूची के साथ नहीं है - इसमें एक पैरामीटर होता है - जिस उदाहरण पर इसे लागू किया जाता है।

+0

ठीक है धन्यवाद यह समझ में आता है लेकिन मेरी समस्या का समाधान नहीं करता है। क्या ऑब्जेक्ट डेटा को सार्वजनिक करने और ऑब्जेक्ट के बाहर आईएसआर बनाने के लिए मैं केवल एक चीज कर सकता हूं? या क्या कोई काम है? –

+0

@AndyProwl अच्छा बिंदु। धन्यवाद –

+1

@FlyingSwissman: मैं अपने उत्तर में एक समाधान का प्रस्ताव दे रहा हूं। दुर्भाग्यवश, जब कोई फ़ंक्शन कच्चे फ़ंक्शन पॉइंटर को स्वीकार करता है तो ऐसा नहीं किया जा सकता है। –

0

आप एक वर्ग के सदस्य समारोह को इंगित करने के boost::function<> या boost::bind<> उपयोग कर सकते हैं:

# include <boost/function.hpp> 
# include <boost/bind.hpp> 
class FunctionClass { 
    private: 
     double a_; 
    public: 
     FunctionClass (const double & a): a_(a){} 
     double multWithA (const double & x) const { return a_*x;} 
     double operator()(const double & x) const { return a_*x;} 
}; 

FunctionClass myClass (2.0); 
double x = 12.0; 
boost :: function <double (FunctionClass *, double)> funcPtr , funcPtr1; 
funcPtr =& FunctionClass :: multWithA; 
funcPtr1 =& FunctionClass :: operator(); 

std :: cout << myClass . multWithA (x) << std :: endl; 
std :: cout << funcPtr (& myClass ,x) << std :: endl; 
std :: cout << funcPtr1 (& myClass ,x) << std :: endl; 

// Bind the function with the class instance 
boost :: function <double (double)> funcPtrNew ; 
funcPtrNew = boost :: bind (funcPtr ,& myClass ,_1); 
std :: cout << funcPtrNew (x) << std :: endl; 
+2

मदद कर सकता हूं, वह नहीं कर सकता, उसे 'शून्य (*) (शून्य)' फ़ंक्शन पॉइंटर पास करना होगा। (मैं arduino पुस्तकालय का एक बड़ा प्रशंसक नहीं हूँ।) – ipc

+0

@ipc शून्य के साथ भी काम करना चाहिए, क्यों नहीं? – 4pie0

+1

क्योंकि उसे कॉल करना है [शून्य संलग्न इंटरप्ट (int, शून्य (*) (शून्य), int)] (http://arduino.cc/en/Reference/AttachInterrupt)। – ipc

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