2012-06-14 14 views
16

मैं अलग-अलग तर्कों के साथ कार्य करने के लिए फ़ंक्शन पॉइंटर असाइन करने में सक्षम होने का तरीका जानने का प्रयास कर रहा हूं।सी ++: तर्क सूचकांक तर्कों की चर संख्या के साथ कार्य करने के लिए

मेरे पास एक समय लूप है जो सशर्त कथन के रूप में कई अलग-अलग कार्यों को लेता है, इसलिए एक ही कोड के अंदर लूप के साथ एकाधिक लिखने की बजाय मैं एक फ़ंक्शन पॉइंटर के साथ एक रखना चाहता हूं। सभी कार्य प्रारूप bool f(...) के प्रारूप हैं। मुझे लगता है कि कुछ कोड सबसे अच्छा उदाहरण देकर स्पष्ट करना होगा कि मैं क्या मतलब है:

int a, b, c, d; 
MyClass* my_class; 

typedef bool (MyClass::*my_fun_t)(); 
my_fun_t my_fun; 

if (condition1) 
    my_fun = &MyClass::function_one(); 
else if (condition2) 
    my_fun = &MyClass::function_two(a, b); 
else if (condition3) 
    my_fun = &MyClass::function_three(a, b, c); 
else if (condition4) 
    my_fun = &MyClass::function_four(a, b, c, d); 

while ((my_class->*my_fun)()) 
{ ... } 

अब इस जाहिर है क्योंकि कार्यों अलग हस्ताक्षर है काम नहीं करता। क्या यह एक समान फैशन में काम करना संभव है? क्या Functoids कुछ मुझे देखना चाहिए?

+0

यदि आप नहीं जानते कि यह कितना तर्क लेता है तो आप उस फ़ंक्शन पॉइंटर को कैसे लागू करें? – mfontanini

+0

ध्यान दें कि फ़ंक्शन पॉइंटर को असाइनमेंट का आपका सिंटैक्स वैसे भी अमान्य है, आप * कार्यों को आविष्कार कर रहे हैं, परिणाम ले रहे हैं, अपने अस्थायी स्टोरेज में पॉइंटर प्राप्त कर रहे हैं, और उस * को * उस * को निर्दिष्ट करें जो आपने पहले घोषित किया था। –

+0

हाँ मुझे पता है कि यह काफी वैध वाक्यविन्यास नहीं है। यह सिर्फ विचार दिखाता है। – jaho

उत्तर

7

आप std::function<> और std::bind() का उपयोग कर सकते हैं।

#include <functional> 

using std::placeholders::_1; 

typedef std::function<bool(MyClass&)> my_fun_t; 
my_fun_t my_fun; 

if (condition1) 
    my_fun = std::bind(&MyClass::function_one, _1); 
else if (condition2) 
    my_fun = std::bind(&MyClass::function_two, _1, a, b); 
else if (condition3) 
    my_fun = std::bind(&MyClass::function_three, _1, a, b, c); 
else if (condition4) 
    my_fun = std::bind(&MyClass::function_four, _1, a, b, c, d); 

while (my_fun(my_class)) { ... } 

ये मानते हैं कि आप सी ++ 11 का उपयोग करेंगे। यदि आप सी ++ 11 का उपयोग नहीं कर सकते हैं लेकिन TR1 का उपयोग कर सकते हैं, std::tr1:: के साथ सभी std:: को प्रतिस्थापित करें। Boost implementation भी है।

+1

उत्कृष्ट, धन्यवाद। मैं सी ++ 11 का उपयोग नहीं कर सकता। बढ़ावा देने के लिए tr1 को पसंद करने का कोई कारण (जिसे मैं वैसे भी उपयोग कर रहा हूं)? – jaho

+1

@Marian TR1 मानक पुस्तकालय में बनाया गया है, बढ़ावा नहीं है। – kennytm

1

मैं विभिन्न तरीकों के साथ कार्यों के लिए फ़ंक्शन पॉइंटर असाइन करने में सक्षम होने का तरीका जानने का प्रयास कर रहा हूं।

आप नहीं कर सकते। फंक्शन पॉइंटर्स एक फ़ंक्शन हस्ताक्षर के लिए विशिष्ट हैं। यह पूरी तरह तार्किक है: आप इस तरह के एक समारोह का आह्वान कैसे करेंगे? (हाँ, सी उनकी घोषणा कितने मापदंडों समारोह है में निर्दिष्ट किए बिना कार्यों लागू की अनुमति देता है, लेकिन यह सी में काम नहीं करता ++ के बाद से यह प्रकार प्रणाली बाधित।)

functoids कुछ मैं पर गौर करना चाहिए रहे हैं?

आम तौर पर हाँ, लेकिन वे इस समस्या को हल नहीं करते हैं।

+0

हम्म, लेकिन परिवर्तनीय तर्क वाले फ़ंक्शन का 'हस्ताक्षर' अभी भी अद्वितीय है, है ना? '...' परिवर्तनीय तर्क भाग कम से कम केवल 'va_list' का एक छद्म कार्य है जो कार्यान्वयन कार्यों के अंदर उपयोग किया जाता है। फ़ंक्शन पॉइंटर के माध्यम से इस तरह के फ़ंक्शन को आमंत्रित करना किसी भी तरह से इस तरह के फ़ंक्शन को सामान्य तरीके से (तर्कों की एक चर सूची के साथ) से अलग नहीं करना चाहिए (नहीं होना चाहिए)। –

+0

@ g-makulik परिवर्तनीय तर्क काम करते हैं, लेकिन यह एक विशिष्ट हस्ताक्षर है, यह अलग-अलग फ़ंक्शन हस्ताक्षरों के लिए बाध्यकारी जैसा नहीं है। –

+0

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

3

आप std::function, एक पॉलिमॉर्फिक फ़ंक्शन ऑब्जेक्ट, और std::bind चाहते हैं ताकि अन्य मज़दूरों के पैरामीटर को तर्क बाध्य करके फ़ंक्शन ऑब्जेक्ट्स बना सकें।

यदि आप सी ++ 11 का उपयोग नहीं कर सकते हैं, तो boost::function और boost::bind बराबर हैं, हालांकि थोड़ा अधिक प्रतिबंधक है।

std::function<bool()> my_fun; 

if (condition1) 
    my_fun = std::bind(&MyClass::function_one, my_class); 
else if (condition2) 
    my_fun = std::bind(&MyClass::function_two, my_class, a, b); 
else if (condition3) 
    my_fun = std::bind(&MyClass::function_three, my_class, a, b, c); 
else if (condition4) 
    my_fun = std::bind(&MyClass::function_four, my_class, a, b, c, d); 

while (my_fun()) 
{ ... } 
+1

यदि आप सी ++ 11 का उपयोग कर सकते हैं तो आप लैम्ब्डा फ़ंक्शंस का भी उपयोग कर सकते हैं और वेरिएबल को संलग्न लेक्सिकल स्कोप से खींच सकते हैं। जो भी आप पसंद करते हैं, मुझे लगता है। – user268396

+0

@ उपयोगकर्ता 268396: शायद। समय के लिए, मैं एक कंपाइलर के साथ फंस गया हूं जो लैम्बडा का समर्थन नहीं करता है, इसलिए मुझे उनके बारे में बहुत कुछ पता नहीं है। –

+0

बूस्ट समाधान ने मेरे लिए काम किया है। धन्यवाद। – jaho

4

यह मेरे लिए काम करता है:

#include <iostream> 
#include <cstdarg> 

using namespace std; 

class MyInterface 
{ 
public: 
    virtual bool func(int argc, ...) = 0; 
}; 

class MyImpl : public MyInterface 
{ 
public: 
    virtual bool func(int argc, ...); 
}; 

bool MyImpl::func(int argc, ...) 
{ 
    va_list varargs; 
    va_start(varargs,argc); 
    cout << "Arguments passed:" << endl; 
    for(int i = 0; i < argc; ++i) 
    { 
     // expect double values 
     double val = va_arg(varargs,double); 
     cout << val << endl; 
    } 
    va_end(varargs); 
    return true; 
} 

typedef bool (MyInterface::*MyFunc)(int, ...); 

int main() { 

    MyImpl impl; 
    MyInterface* interface = &impl; 
    MyFunc pfunc = &MyInterface::func; 

    if(!(interface->*pfunc)(2,double(3.14),double(2.72))) 
    { 
     return 1; 
    } 
    return 0; 
} 

आउटपुट:

Arguments passed: 
3.14 
2.72 

जाहिर है आप यह घोषित और के लिए (सदस्य) अलग-अलग तर्कों का उपयोग कार्यों समारोह संकेत का उपयोग कर सकते हैं।

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