2011-05-24 15 views
6

मुझे इस बात पर रूचि है कि लुबाइंड रैपर lua_State *L के बिना फ़ंक्शन को पास करना संभव बनाता है और लुआ स्टैक का उपयोग नहीं करता है।लुबाइंड कैसे काम करता है?

कैसे Luabind करता है:

  1. फ़ंक्शन पैरामीटर गिनती?
  2. फ़ूआ पैरामीटर को लुआ स्टैक से लिंक करें?
  3. उन वर्गों

मैं एक अन्य पुस्तकालयों के लिए Luabind तरह बाध्यकारी बनाने का प्रयास कर नहीं कर रहा हूँ जोड़ देते हैं। मैं बस सोच रहा हूं कि उन्होंने ऐसा कैसे किया। बस एक जिज्ञासु आदमी।

उत्तर

0

मैं luabind से परिचित नहीं हूं, लेकिन "रैपर" का पूरा विचार यह है कि यह कुछ निचले स्तर के अमूर्तता के शीर्ष पर बनाया गया है, इसे encapsulating। luabind लगभग निश्चित रूप से lua_Stateआंतरिक रूप से का उपयोग करें।

0

the manual से:

पहली बात करने की ज़रूरत है luabind::open(lua_State*) जो कार्यों लुआ से कक्षाएं बनाने के लिए रजिस्टर करेंगे कहते हैं, और luabind द्वारा इस्तेमाल किया कुछ राज्य वैश्विक ढांचे को प्रारंभ करने के लिए है।

तो मेरी (कुछ शिक्षित) अनुमान है कि आप luabind::open काम करते है और यह शेष कार्यों में उपयोग के राज्य संचित करता है। (सुराग "कुछ राज्य-वैश्विक संरचनाओं को शुरू करने" में निहित है।)

3

luabind परिचित int luafunction(lua_State* L) प्रोटोटाइप के लिए टेम्पलेट रैपर फ़ंक्शन है जो सी एपीआई स्वीकार करता है। संक्षेप में, lua_CFunction आपके लिए बनाया गया है। कॉल करने के लिए वास्तविक सी या सी ++ फ़ंक्शन को रैपर के ऊपरी हिस्से के रूप में संग्रहीत किया जा सकता है। सी ++ सदस्य फ़ंक्शन के मामले में, this पॉइंटर को पहले तर्क से लिया जा सकता है।

उदाहरण कोड upvalues ​​का उपयोग कर एक सी समारोह लपेटकर:

template<typename R, typename T1> 
int arg1wrapper(lua_State* L) 
{ 
    typedef R (*F)(T1); 
    F func = (F)lua_touserdata(L, lua_upvalueindex(1)); 
    R retValue = func(luaToC<T1>(L, 1)); 
    push(L, retValue); 
    return 1; 
} 

// example use 
template<typename R, typename T1> 
void push(R (*func)(T1)) 
{ 
    lua_pushlightuserdata(L, func); 
    lua_pushcclosure(L, &arg1wrapper<R, T1>, 1); 
} 

(।। luaToC टेम्प्लेटेड समारोह हर C और C++ टाइप पुस्तकालय का समर्थन करने का इरादा रखता के लिए विशेष किया जाएगा push समारोह इसी तरह अतिभारित किया जाएगा)

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

(ध्यान दें कि C++ 0x में आप एक ही टेम्पलेट के साथ मानकों की किसी भी राशि का समर्थन करने के variadic टेम्पलेट का उपयोग कर सकते हैं)

13

अच्छा प्रश्न है। मुझे कुछ अस्पष्ट विचार था कि यह कितना लुभावना करता है, लेकिन मुझे पूरी तरह से और सटीक उत्तर देने के लिए पर्याप्त जानकारी नहीं थी।एक IDE और डीबगर मैं निम्नलिखित बहुत ही सरल टुकड़ा चीर-फाड़ शुरू कर दिया साथ सशस्त्र:

struct C 
{ 
    int i; 
    int f(int x, const char* s) 
}; 

    lua_State* L = luaL_newstate(); 

open(L); 
module(L) 
[ 
    class_<C>("C") 
     .def_readwrite("index", &C::i) 
     .def("f", &C::f) 
]; 
सूचना के लिए

पहली बात कि L एक बहुत luabind को पारित कर दिया है, open करने के लिए कॉल लुआ राज्य में कुछ वैश्विक बनाता है: __luabind_classes टाइप उपयोगकर्ता उपयोगकर्ता और दो फ़ंक्शंस class और property। लुबाइंड वैश्विक चर का उपयोग नहीं कर रहा है - इसकी हर चीज को लुआ पर्यावरण में बचाया जाता है।

अब हम module(L)[...] पर पहुंचते हैं। मूल कोड, सबसे अच्छा विवरण है पहले यहां module है: पर्याप्त

inline module_ module(lua_State* L, char const* name = 0) 
{ 
    return module_(L, name); 
} 

सरल, यहाँ module_ है:

class LUABIND_API module_ 
{ 
public: 
    module_(lua_State* L_, char const* name); 
    void operator[](scope s); 

private: 
    lua_State* m_state; 
    char const* m_name; 
}; 

तो क्या हमारे छोटे से कार्यक्रम करता कॉल ऑपरेटर [] कुछ परिभाषाओं के साथ module_ वर्ग पर है (यह scope पैरामीटर है), लेकिन module_ कक्षा जानता है जिसमें लुआ राज्य संचालित है।

struct LUABIND_API scope 
{ 
    //... 
    explicit scope(detail::registration* reg); 
    scope& operator,(scope s); 
    void register_(lua_State* L) const; 
private: 
    detail::registration* m_chain; 
}; 

scopedetail::registration नोड्स के एक लिंक्ड सूची बनाने जा रहा है, उस सूची operator, का उपयोग कर से आता है: scope वर्ग भी दिलचस्प (कुछ भागों को हटा दिया जाता है और कुछ थोड़ा सरलीकृत) को देखने के लिए है। इसलिए जब एक करता है module(L) [class_<...>..., class_<...>...], class_ जो scope से विरासत initializes एक detail::registration उदाहरण के साथ उसके आधार है, तो scope की अल्पविराम ऑपरेटर सभी पंजीकरण की कोई लिंक की गई सूची बनाता है, इस module_::operator[] जो scope::register_ जो बारी में श्रृंखला विश्लेषण करता है और कहता है register_ कॉल करने के लिए पारित हो जाता है उन सभी detail::registration वस्तुओं पर। lua_State हमेशा register_ पर भेज दिया गया है।

पुhew। अब देखते हैं कि क्या होता है जब कोई class_<C>("C").def("f", &C::f) करता है। यह में detail::registration सदस्य में एक निश्चित नाम के साथ class_<C> का एक उदाहरण बनाता है। class_::def विधि कॉलिंग reg संरचना और whatnot में लिखते हैं, लेकिन यहाँ def से कॉल श्रृंखला में एक बहुत ही दिलचस्प लाइन गहरी है:

  object fn = make_function(
       L, f, deduce_signature(f, (Class*)0), policies); 

ओह, deduce_signature, मैं वास्तव में है कि देखना चाहती थी। अब मैं इसे unsee करना चाहते हैं, लेकिन जिस तरह से यह काम करता है यह है: अंधेरे पूर्वप्रक्रमक टोना को बढ़ावा देने के द्वारा सहायता प्राप्त (BOOST_PP_ITERATE और कुछ अन्य उपयोगिताओं) के माध्यम से के बाद एक और LUABIND_MAX_ARITY के बीच प्रत्येक N के लिए उत्पन्न होता है:

template <class R, class T, class A1, classA2, ..., classAN> 
boost::mpl::vectorN_PLUS_2<R, T, A1, A2, ..., AN> // type of return value 
    deduce_signature(R(T::*)(A1, A2, ..., AN)) 
    { 
      return boost::mpl::vectorN_PLUS_2<R, T, A1, A2, ..., AN>() 
    } 

फिर से, इस तरह का एक कार्य सभी एन के लिए 1 और LUABIND_MAX_ARITY के बीच जेनरेट किया गया है जो डिफ़ॉल्ट रूप से 10 है। कॉन्स्ट विधियों, वर्चुअल रैपर और फ्री फ़ंक्शंस को संभालने के लिए कुछ ओवरलोड हैं, जिसका अर्थ है कि लगभग 50 deduce_signature फ़ंक्शंस हैं जो आपके स्रोतों में प्रीप्रोसेसर के ठीक बाद और संकलन शुरू होने से पहले समाप्त होते हैं। वहां से, यह def पर भेजे गए कार्यों के लिए सही deduce_signature अधिभार चुनने के लिए संकलक का काम है और यह सही boost::mpl::vectorX प्रकार वापस करेगा। वहां से make_function कुछ भी कर सकता है - इसमें पैरामीटर प्रकारों की एक [संकलित समय] सूची है और कुछ और टेम्पलेट जादू के माध्यम से इन्हें गिना जाता है, लुआ मूल्यों में परिवर्तित किया जाता है और इसी तरह से।

यह वह जगह है जहां मैं रुक जाऊंगा।जांच लुबाइंड 0.8.1 पर आधारित है। अधिक उत्तरों के लिए लुबाइंड के कोड को ब्राउज़/डिबग करने के लिए स्वतंत्र महसूस करें - इसमें कुछ समय लगता है लेकिन स्टाइल में उपयोग करने के बाद यह मुश्किल नहीं है :) शुभकामनाएं।

टीएल; डीआर: जादू ... काला जादू

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