2012-12-26 21 views
7

(नोट:।जैसा कि पहले ही टैग से स्पष्ट किया जाना चाहिए, इस सख्ती सेसी ++ 03 हैहाँ, मुझे पता है, लैम्ब्डा यह सब दर्द दूर जाना बनाता है (और नए में लाता है प्रकार, मैं शर्त लगाता हूं), लेकिन यह एक एम्बेडेड सिस्टम है, जिसमें 9 0 के ओएस संस्करण के साथ, और मुझे बताया गया है कि मुझे खुशी होनी चाहिए कि मेरे पास सी ++ 03 कंपाइलर (जीसीसी 4.1.एक्स, बीटीडब्लू) है, या सी ++ संकलक बिल्कुल। कृपया सी ++ 11 समाधान पोस्ट करने से दूर रहें। वास्तव में इसे रगड़ने की कोई ज़रूरत नहीं है।
इसके अलावा, std::bind(), std::function() इत्यादि वास्तव में std::tr1 में हैं, लेकिन मैंनेसंपादित कियाउपसर्ग, क्योंकि मैंने सोचा था कि यह कोड को अधिकतर शोर जोड़ता है।
)std :: bind के साथ यह कैसे करें?

मेरे पास कुछ सर्वर जैसी चीज है जो मुझे कार्यों को पंजीकृत करने की आवश्यकता है और मुझे उन्हें कुछ ऑब्जेक्ट के समान, लेकिन थोड़ा अलग, कॉल करने के लिए अनुकूलित करने की आवश्यकता है। इन कार्यों में अलग-अलग तर्क सूचियां हैं। सर्वर "जानता है" कि जब मैं किसी फ़ंक्शन को पंजीकृत करने का प्रयास करता हूं तो यह केवल सही हस्ताक्षर के साथ स्वीकार करता है (जैसा कि std::function के रूप में सही है, वह है), टेम्पलेट तर्क के रूप में पारित कुछ जादू टैग के आधार पर।

यहाँ कोड का एक स्केच है:

// this I just use 
class server { 
public: 
    template<unsigned int MagicTag> 
    bool register_call(typename some_traits_type<MagicTag>::func_type); 
}; 

// this needs to be called from the server 
class X { 
public: 
    bool foo(); 
    bool bar(std::string&); 
    bool baz(int); 
}; 

// this is the glue 
class Y { 
public: 
    Y(X& x) : x_(x) { 
     register_call<MAGIC_FOO>(&Y::foo ); 
     register_call<MAGIC_BAZ>(&Y::bar, _1); 
     register_call<MAGIC_FBZ>(&Y::baz, _1); 
    } 

private: 
    X&     x_; 

    template<unsigned int MagicTag, typename Function> 
    bool register_call(Function function) { 
     somewhere->register_call<MagicTag>(std::bind(function 
                , this)); 
    } 
    template<unsigned int MagicTag, typename Function, typename PlaceHolder1> 
    bool register_call(Function function, PlaceHolder1 place_holder1) { 
     somewhere->register_call<MagicTag>(std::bind(function 
                , this 
                , place_holder1)); 
    } 

    int foo()    {return x_.foo() ? MAGIC_OK : MAGIC_FAILED;} 
    int bar(std::string& s) {return x_.bar(s) ? MAGIC_OK : MAGIC_FAILED;} 
    int baz(int i)   {return x_.baz(i) ? MAGIC_OK : MAGIC_FAILED;} 
}; 

यह वास्तव में काम करता है, लेकिन वास्तविकता में वहाँ जिस तरह से अधिक कार्य हैं और एक कठिन copy'n'paste प्रयास के रूप में यह कर गरिमा की मेरी भावना का अपमान और सुगंधित कोड पैदा करता है। चूंकि ये सभी फ़ंक्शंस वही कार्य करते हैं, जिसमें केवल वे फंक्शन होते हैं, जिनके पास वे कॉल करते हैं और उनके पास तर्क होते हैं, या पास नहीं होते हैं, इसलिए मुझे std::bind() के पीछे अंतर छिपाने के लिए उन्हें एक पैरामीट्रिज्ड फ़ंक्शन में फोल्ड करने में सक्षम होना चाहिए। इसे विफल करने के बाद, मैंने पहले किसी भी पैरामीटर के बिना सभी कार्यों के लिए ऐसा किया (जैसे foo()), जो कि भारी बहुमत है।

int call_it(std::function<bool()> f) {return f() ? MAGIC_OK : MAGIC_FAILED;} 

और इसे करने के लिए एक तर्क के रूप X में उचित समारोह के लिए बाध्य:

तो मैं रूट करने के लिए foo() की तरह समारोह की सभी कॉल्स X में एक भी समारोह Y::call_it कि थकाऊ हिस्सा करता है के माध्यम से चाहता था:

register_call<MAGIC_FOO>(&X::foo); // note the X! 

// (this is wrong) 
somewhere->register_call<MagicCode>(std::bind(std::bind(&Y::call_it 
                 , this 
                 , function) 
               , std::ref(x_)); 

जाहिर है, यह गलत है, और इसलिए इस को हल करने पर मेरे सारे अन्य प्रयास कर रहे हैं। (मैं अब 10 सप्ताह के लिए std::bind() के साथ खेल रहा हूं, इसलिए कृपया मेरे साथ भालू)। अंत में मैं std::function के अपरिपक्व गलतियों से उल्लसित त्रुटि संदेशों की अविश्वसनीय भूलभुलैया में खो गया जो एक बड़े आदमी को आँसू में नीचे ला सकता है और कम से कम एक वर्ष के लिए एक संकीर्ण और उसके विस्तारित परिवार को खिलाना चाहिए।

तो इससे पहले कि मैं kill myself out of sheer frustration और अपने बच्चों को अनाथ - मैं यह कैसे कर सकता हूं?

+0

मैंने कभी std :: bind का उपयोग नहीं किया है। एक कबुलीजबाब के लिए यह कैसा है। लेकिन आप नहीं चाहते हैं 'register_call (std :: bind (& y :: call_it, this, std :: bind (ptmf, std :: ref (x_)); '? – rici

+0

@rici: हां, ज़ाहिर है, तुम सही हो। [मैंने इसे पहले ही देखा है] (http://chat.stackoverflow.com/transcript/10?m=6878122#6878122।) यह बस इतना है कि मैं उस दीवार के खिलाफ अपने सिर को टक्कर लगी है घंटों, और यह काम करने के लिए 1001 वें प्रयास के बीच में भ्रमित स्थिति है, जो मैंने तय किया था कि मुझे इसके बारे में पूछना होगा। समस्या यह है कि मैं इसे दूसरी तरफ काम नहीं कर सकता , या तो। _Sigh._ – sbi

+1

मुझे लगता है कि मैंने कभी std :: bind का उपयोग नहीं किया है। टेम्पलेट मेटाडेबगिंग पागल है। या यह आपको पागल कर देता है। शायद यही कारण है कि सभी मानक लाइब्रेरी कार्यान्वयन घटिया हैं। शुभकामनाएं! – rici

उत्तर

3

जो मैं इकट्ठा करता हूं, उससे Y::call_it() पर std::function ऑब्जेक्ट उचित रूप से बाध्य होना चाहता है। यह देखते हुए कि आपका आंतरिक कार्य विभिन्न तर्कों को लेता है, ऐसे मामलों के लिए std::function<bool()> जेनरेटर बनाना आवश्यक है जहां अतिरिक्त तर्क पारित किए जा रहे हैं।मान लिया जाये कि X वस्तु पंजीकरण समय में बाध्य किया जा सकता है, अतिरिक्त तर्क के बिना एक सदस्य समारोह के पंजीकरण सीधे आगे है:

template <int Magic, typename RC> 
void register_call(RC (X::*member)()) { 
    somewhere->register_call<Magic>(
     std::bind(&Y::call_it, this, 
      std::function<bool()>(std::bind(member, 
              std::ref(this->x_))))); 
} 

जब एक या अधिक तर्क गुजर, यह कॉल समय की बात है एक std::function<bool()> वस्तु बनाने के लिए आवश्यक है, क्योंकि अतिरिक्त तर्क को बाध्य करने की जरूरत है। मुझे नहीं लगता कि है कि यह एक सहायक समारोह के बिना किया जा सकता है लेकिन यह तर्क की संख्या प्रति एक सहायक समारोह के साथ किया जा सकता है:

template <typename RC, typename Arg0> 
static std::function<bool()> 
bind_argument(RC (X::*member)(Arg0), X& x, Arg0 const& arg0) { 
    return std::bind(member, std::ref(x), arg0); 
} 
template <int Magic, typename RC, 
      typename Arg0, typename PlaceHolder> 
void register_call(RC (X::*member)(Arg0), PlaceHolder pc) { 
    somewhere->register_call<Magic>(
     typename some_traits_type<Magic>::type(
      std::bind(&Y::call_it, this, 
         std::bind(&bind_argument<RC, Arg0>, member, 
           std::ref(this->x_), pc)))); 
} 

सहायक समारोह एक अतिरिक्त तर्क बाध्य किया जा रहा है एक समारोह पैदा करता है। ध्यान दें कि फ़ंक्शन बाध्य किया गया है उसी प्रकार के रूप में बनाया गया है जैसा कि रजिस्टर फ़ंक्शन द्वारा अपेक्षित है: यह आवश्यक है, उदाहरण के लिए, अतिरिक्त, अनदेखा, तर्क लेने वाला फ़ंक्शन बनाने के लिए।

नीचे एक परीक्षण कार्यक्रम है जिसे मैं देखने के लिए उपयोग करता था कि चीजें संकलित होती हैं या नहीं। मेरे पास TR1 के साथ एक C++ 2003 कंपाइलर नहीं है और कोड को C++ 2011 कंपाइलर के साथ संकलित किया है। हालांकि, मुझे नहीं लगता कि मैंने सी ++ 2011 एक्सटेंशन का उपयोग किया है जो सी ++ 2003 से TR1 के साथ उपलब्ध नहीं है।

bind(&Y::call_it, this, bind(&X::foo, ref(x_))) 

क्योंकि संकलक अनुमान नहीं कर सकते हैं:

#include <functional> 

enum { 
    MAGIC_OK, 
    MAGIC_FAILED, 
    MAGIC_FOO, 
    MAGIC_BAR, 
    MAGIC_FBZ, 
    MAGIC_BAZ 
}; 

template <int> struct server_traits; 
template <> struct server_traits<MAGIC_FOO> { 
    typedef std::function<bool()> type; 
}; 
template <> struct server_traits<MAGIC_BAR> { 
    typedef std::function<bool(std::string&)> type; 
}; 
template <> struct server_traits<MAGIC_FBZ> { 
    typedef std::function<bool(long)> type; 
}; 
template <> struct server_traits<MAGIC_BAZ> { 
    typedef std::function<bool(std::string, long)> type; 
}; 


// this I just use 
class server { 
public: 
    template<unsigned int MagicTag> 
    bool register_call(typename server_traits<MagicTag>::type) { 
     return true; 
    } 
}; 

server s; 
server* somewhere = &s; 

// this needs to be called from the server 
class X { 
public: 
    bool foo() { return true; } 
    bool bar(std::string&) { return true; } 
    bool baz(int) { return true; } 
}; 

// this is the glue 
class Y { 
public: 
    Y(X& x) : x_(x) { 
     register_call<MAGIC_FOO>(&X::foo ); 
     register_call<MAGIC_BAR>(&X::bar, std::placeholders::_1); 
     register_call<MAGIC_FBZ>(&X::baz, std::placeholders::_1); 
     register_call<MAGIC_BAZ>(&X::baz, std::placeholders::_2); 
    } 

private: 
    X& x_; 

    int call_it(std::function<bool()> f) { 
     return f() ? MAGIC_OK : MAGIC_FAILED; 
    } 

    template <int Magic, typename RC> 
    void register_call(RC (X::*member)()) { 
     somewhere->register_call<Magic>(
      std::bind(&Y::call_it, this, 
       std::function<bool()>(std::bind(member, 
               std::ref(this->x_))))); 
    } 
    template <typename RC, typename Arg0> 
    static std::function<bool()> 
    bind_argument(RC (X::*member)(Arg0), X& x, Arg0 const& arg0) { 
     return std::bind(member, std::ref(x), arg0); 
    } 
    template <int Magic, typename RC, 
       typename Arg0, typename PlaceHolder> 
    void register_call(RC (X::*member)(Arg0), PlaceHolder pc) { 
     somewhere->register_call<Magic>(
      typename server_traits<Magic>::type(
       std::bind(&Y::call_it, this, 
          std::bind(&bind_argument<RC, Arg0>, member, 
            std::ref(this->x_), pc)))); 
    } 
}; 

int main() 
{ 
    X x; 
    Y y(x); 
} 
+0

धन्यवाद, डाइटमार! उन लोगों को 'std :: bind()' को कॉल करने के बिना अच्छी तरह से घोंसला नहीं है, मुझे पहले से ही [चैट में] पता चला था (http://chat.stackoverflow.com/transcript/10?m=6878274#6878274) । हालांकि, मैं अभी भी तर्क लेने वाले कार्यों पर संकलक के साथ लड़ रहा हूं, इसलिए आपका समाधान वास्तव में बहुत स्वागत है। – sbi

+0

दुर्भाग्यवश, मैं आपके कोड को संकलित करने के लिए नहीं मिल सकता। फ़ंक्शन के लिए 'std :: स्ट्रिंग और' कंपाइलर छाल 'को कॉल करने के लिए कोई मिलान करने वाला फ़ंक्शन' बाइंड (<अनसुलझा अधिभारित फ़ंक्शन प्रकार>, बूल (एक्स :: * और) (std :: string &), std :: context_wrapper , std :: _ प्लेसहोल्डर <1> और) ''। दो और त्रुटियां हैं।ऐसा लगता है कि 'Arg0 const & arg0'' से परेशान है, जो न तो 'int' और न ही 'std :: string' 'ठीक है। – sbi

+0

यह निश्चित रूप से जीसीसी का उपयोग कर मेरे लिए संकलक करता है। क्लैंग के साथ कोड को संकलित करने का प्रयास करना एक त्रुटि के कारण विफल रहता है जो कि libcxx के संस्करण के साथ प्रतीत होता है। हालांकि, 'Arg0' पैरामीटर पर' const & 'को हटाने के लिए' bind_argument() 'की घोषणा को बदलने का प्रयास करें (' const & 'एक प्रयास से बाएं ओवर है जहां मैंने पैरामीटर घटाया और 'Arg0' सही है वैसे भी टाइप करें। –

1

चैट चैनल लिंक से, यह आप इस तथ्य को समस्या नीचे उबला हुआ किए हैं, जैसे कि एक नेस्टेड बाँध संकलन नहीं करता लग रहा है इस मामले में आंतरिक बाइंड() के रूप में हस्ताक्षर (< बूल()> के रूप में। यह बजाय काम कर सकते हैं:

bind(&Y::call_it, this, function<bool()>(bind(&X::foo, ref(x_)))) 

और अगर यह होता है, आप की तरह

template<unsigned int MagicTag, typename Function > 
bool register_call(Function func) { 
    somewhere->register_call<MagicTag>(
     bind(&Y::call_it, this, function<bool()>(bind(func, ref(x_))))); 
} 

कुछ होगा हालांकि मैं लग रहा है कि दूसरे टेम्पलेट पैरामीटर किसी भी तरह आवश्यक नहीं हो सकता मिलता है। मुख्य विचार है कि std :: function को दो std :: bind के बीच डालना है।

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