• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-4  評(píng)論-40  文章-117  trackbacks-0


            轉(zhuǎn)

            LuaBind --最強(qiáng)大的Lua C++ Bind


            1 介紹
            LuaBind 是一個(gè)幫助你綁定C++和Lua的庫.她有能力暴露 C++ 函數(shù)和類到 Lua . 她也有
            能力支持函數(shù)式的定義一個(gè)Lua類,而且使之繼承自C++或者Lua. Lua類可以覆寫從 C++ 基類
            繼承來的虛函數(shù). 她的目標(biāo)平臺(tái)是Lua 5.0 ,不能支持Lua 4.0 .

            她利用模板原編程技術(shù)實(shí)現(xiàn).這意味著,你不需要額外的預(yù)處理過程去編譯你的工程(編譯器
            會(huì)替你完成全部的工作).這還意味著,你也不需要(通常)知道你注冊(cè)的每一個(gè)函數(shù)的精確的簽名.
            因?yàn)?LuaBind庫會(huì)在編譯時(shí)生成所需的代碼.這樣做的不利點(diǎn)是,編譯時(shí)間會(huì)隨著需要注冊(cè)的
            文件的數(shù)目增加而增加.因此建議你把所有的需要注冊(cè)的東西放到一個(gè)cpp文件里面.

            LuaBind 遵循 MIT 協(xié)議 發(fā)布.

            我們非常希望聽說有工程使用了LuaBind, 請(qǐng)告訴我們,如果你的工程使用了LuaBind.

            主要的反饋渠道是 LuaBind郵件列表 .
            在 irc.freenode.net還可以找到一個(gè)IRC頻道 #luabind .

            2 功能

            LuaBind支持:

            * 重載自由函數(shù)
            * C++類導(dǎo)入Lua
            * 重載成員函數(shù)
            * 操作符
            * 屬性
            * 枚舉
            * Lua函數(shù)導(dǎo)入C++
            * Lua類導(dǎo)入C++
            * Lua類(單繼承)
            * 從Lua或C++類繼承
            * 覆寫C++類的虛函數(shù)
            * 注冊(cè)類型間隱式的類型轉(zhuǎn)換
            * 最好匹配式簽名匹配
            * 返回值策略和參數(shù)策略

            3 可移植性

            LuaBind 已經(jīng)通過下面的編譯器環(huán)境的測試:

            Visual Studio 7.1
            Visual Studio 7.0
            Visual Studio 6.0 (sp 5)
            Intel C++ 6.0 (Windows)
            GCC 2.95.3 (cygwin)
            GCC 3.0.4 (Debian/Linux)
            GCC 3.1 (SunOS 5.8)
            GCC 3.2 (cygwin)
            GCC 3.3.1 (cygwin)
            GCC 3.3 (Apple, MacOS X)
            GCC 4.0 (Apple, MacOS X)


            LuaBind被確認(rèn)不能在 GCC 2.95.2 (SunOS 5.8) 下工作.
            Metrowerks 8.3 (Windows) 可以編譯LuaBind,但是通不過常量測試.這就意味著常量
            成員函數(shù)被視同非常量成員函數(shù).
            如果你測試了LuaBind和其他未列出的編譯器的兼容性,請(qǐng)告訴我們你的結(jié)果.

            4 構(gòu)建LuaBind

            為了抑制LuaBind的編譯時(shí)間最好是將其編譯為一個(gè)庫. 這意味著你要不編譯并連接LuaBind
            庫要不就添加其所有源碼到你的工程里面.你必須確保LuaBind目錄在你的編譯器包含目錄中.
            LuaBind需要Boost 1.32.0 或者 1.33.0 (只需要頭文件即可). LuaBind還需要Lua.

            官方的構(gòu)建LuaBind的方式是通過 Boost.Build V2 . 為此,你需要設(shè)置兩個(gè)環(huán)境變量:
            BOOST_ROOT 指向你的Boost安裝目錄
            LUA_PATH 指向你的Lua目錄.編譯系統(tǒng)將假定包含文件和庫文件分別放在
            $(LUA_PATH)/include/ 和 $(LUA_PATH)/lib/.

            為了向后兼容性,LuaBind在根目錄下還保留了一個(gè)makefile.這可以構(gòu)建庫和測試程序.如果
            你正在使用一個(gè)UNIX系統(tǒng)(或者 cygwin),他們將使得構(gòu)建LuaBind靜態(tài)庫變得很簡單.如果
            你正在使用 Visual Studio ,很簡單的包含 src 目錄下的文件到你的工程即可.

            構(gòu)建LuaBind的時(shí)候,你可以設(shè)定一些選項(xiàng)來使得庫更加符合你的需求.特別重要的是,你的應(yīng)用
            程序也必須使用和庫一樣的設(shè)定.可用的選項(xiàng)的介紹參見 Build options 章節(jié).

            如果你希望改變?nèi)笔〉脑O(shè)置,推薦你通過修改命令行參數(shù)的方式來實(shí)現(xiàn).(在Visual Studio
            的工程設(shè)置項(xiàng)里面).

            5 基本使用

            為了使用LuaBind, 你必須包含 lua.h 和 LuaBind 的主要頭文件:
            extern "C"
            {
            #include "lua.h"
            }

            #include

            這些頭文件提供了注冊(cè)函數(shù)和類的功能. 如果你只是想獲得函數(shù)或者類的支持,你可以分開
            包含 luabind/function.hpp 和 luabind/class.hpp:
            #include
            #include
            你需要去做的第一件事是 調(diào)用 luabind::open(lua_State*), 由此注冊(cè)可以在Lua創(chuàng)建類
            的函數(shù)并初始化 LuaBind需要使用的 狀態(tài)機(jī)全局結(jié)構(gòu). 如果你不調(diào)用這個(gè)函數(shù), 你會(huì)在后面
            觸發(fā)一個(gè) 斷言 . 不沒有一個(gè)對(duì)應(yīng)的關(guān)閉函數(shù).因?yàn)?一旦一個(gè)類被注冊(cè)到Lua,真沒有什么好
            的方法去移除它.部分原因是任何剩余的類實(shí)例都將依賴其類. 當(dāng)狀態(tài)機(jī)被關(guān)閉的時(shí)候,所有
            的一切都將被清理干凈.

            LuaBind 的頭文件不會(huì)直接包含 Lua.h , 而是透過 . 如果你
            出于某種原因需要包含其他的Lua頭文件,你可以修改此文件.

            5.1 Hello World
            新建一個(gè)控制臺(tái)DLL工程, 名字是 luabind_test.
            #include
            #include
            #include

            extern "C"
            {
            #include "lua.h"
            #include "lauxlib.h"
            }

            void greet()
            {
            std::cout << "hello world!n";
            }

            extern "C" int luaopen_luabind_test(lua_State* L)
            {
            using namespace luabind;

            open(L);

            module(L)
            [
            def("greet", &greet)
            ];

            return 0;
            }

            把生成的DLL和lua.exe/lua51.dll放在同一個(gè)目錄下.
            Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
            > require "luabind_test"
            > greet()
            Hello world!
            >

            6 作用域

            注冊(cè)到Lua里面的所有東西要不注冊(cè)于一個(gè)名空間下(Lua table)要不注冊(cè)于全局作用域(lua module).
            所有注冊(cè)的東西必須放在一個(gè)作用域里面.為了定義一個(gè)模塊, luabind::module 類必須被使用.
            使用方式如下:
            module(L)
            [
            // declarations
            ];
            這將會(huì)注冊(cè)所有的函數(shù)或者類到 Lua 全局作用域. 如果你想要為你的模塊設(shè)定一個(gè)名空間(類似標(biāo)準(zhǔn)模塊),
            你可以給構(gòu)造函數(shù)設(shè)定一個(gè)名字,例如:
            module(L, "my_library")
            [
            // declarations
            ];
            這里所有的申明都將被放置在 my_libary 表.

            如果你想要嵌套名空間,你可以用 luabind::namespace_ 類. 它和 luabind::module 類似,除了構(gòu)造器
            沒有l(wèi)ua_State* 輸入?yún)?shù).用例如下:
            module(L, "my_library")
            [
            // declarations

            namespace_("detail")
            [
            // library-private declarations
            ]
            ];

            你可能會(huì)想到,下面兩個(gè)聲明是等價(jià)的:
            module(L)
            [
            namespace_("my_library")
            [
            // declarations
            ]

            ];
            module(L, "my_library")
            [
            // declarations
            ];
            每一個(gè)聲明必須用逗號(hào)分隔,例如:
            module(L)
            [
            def("f", &f),
            def("g", &g),
            class_("A")
            .def(constructor),
            def("h", &h)
            ];

            更多實(shí)際的例子請(qǐng)參閱 綁定函數(shù)到Lua 和 綁定類到Lua 章節(jié).

            請(qǐng)注意, (如果你對(duì)性能有很高的需求)把你的函數(shù)放到表里面將增加查找函數(shù)的時(shí)間.

            7 綁定函數(shù)到Lua

            為了綁定函數(shù)到Lua,你可以使用函數(shù) luabind::def(). 它的聲明如下:
            template
            void def(const char* name, F f, const Policies&);
            * name 是該函數(shù)在Lua里面的名字
            * F 是該函數(shù)的指針
            * 策略參數(shù)是用來描述怎樣處理該函數(shù)參數(shù)和返回值的.這是一個(gè)可選參數(shù),參見 策略 章節(jié).

            下面的例子演示注冊(cè)函數(shù) float std::sin(float):
            module(L)
            [
            def("sin", &std::sin)
            ];

            7.1 重載函數(shù)

            如果你有同名函數(shù)需要注冊(cè)到Lua, 你必須顯示的給定函數(shù)的簽名.
            這可以讓C++知道你指定的是哪一個(gè)函數(shù). 例如, 如果你有兩個(gè)函數(shù),
            int f(const char*) 和 void f(int).
            module(L)
            [
            def("f", (int(*)(const char*)) &f),
            def("f", (void(*)(int)) &f)
            ];

            7.2 簽名匹配

            LuaBind 將會(huì)生成代碼來檢查Lua棧的內(nèi)容是否匹配你的函數(shù)的簽名. 它會(huì)隱式的在
            派生類之間進(jìn)行類型轉(zhuǎn)換,并且它會(huì)按照盡量少進(jìn)行隱式類型轉(zhuǎn)換的原則經(jīng)行匹配.在
            一個(gè)函數(shù)調(diào)用中,如果函數(shù)是重載過的,并且重載函數(shù)的參數(shù)匹配分不出好壞的話
            (都經(jīng)行同樣次數(shù)的隱式類型轉(zhuǎn)換),那么將產(chǎn)生一個(gè)二義性錯(cuò)誤.這將生成一個(gè)運(yùn)行時(shí)
            錯(cuò)誤,程序掛起在產(chǎn)生二義性調(diào)用的地方.一個(gè)簡單的例子是,注冊(cè)兩個(gè)函數(shù),一個(gè)函數(shù)
            接受一個(gè)int參數(shù),另外一個(gè)函數(shù)接受一個(gè)float參數(shù). 因?yàn)長ua將不區(qū)別浮點(diǎn)數(shù)和整形數(shù),
            所以他們都是匹配的.

            因?yàn)樗械闹剌d是被測試過的,這將總是找到最好的匹配(不是第一個(gè)匹配).這樣意味著,
            LuaBind可以處理簽名的區(qū)別只是const和非const的重載函數(shù).

            例如,如果如下的函數(shù)和類被注冊(cè):
            struct A
            {
            void f();
            void f() const;
            };

            const A* create_a();
            為了正確處理所有權(quán)轉(zhuǎn)移問題,create_a()將用來適配返回值策略.
            參見 策略 章節(jié).
            -Linker Lin 4/5/08 6:32 PM

            struct B: A {};
            struct C: B {};

            void g(A*);
            void g(B*);


            執(zhí)行以下 Lua 代碼即結(jié)果:

            a1 = create_a()
            a1:f() -- 常量版本被調(diào)用

            a2 = A()
            a2:f() -- 非常量版本被調(diào)用

            a = A()
            b = B()
            c = C()

            g(a) -- calls g(A*)
            g(b) -- calls g(B*)
            g(c) -- calls g(B*)


            7.3 調(diào)用Lua函數(shù)

            為了調(diào)用一個(gè)Lua函數(shù), 你可以或者用 call_function() 或者用 一個(gè)對(duì)象(object).

            template
            Ret call_function(lua_State* L, const char* name, ...)
            template
            Ret call_function(object const& obj, ...)


            call_function()函數(shù)有兩個(gè)重載版本.一個(gè)是根據(jù)函數(shù)的名字來調(diào)用函數(shù),
            另一個(gè)是調(diào)用一個(gè)可以作為函數(shù)調(diào)用的Lua值.

            使用函數(shù)名來調(diào)用的版本只能調(diào)用Lua全局函數(shù). "..."代表傳遞給Lua函數(shù)的
            可變個(gè)數(shù)的參數(shù). 這使得你可以指定調(diào)用的策略.你可以通過 operator[] 來實(shí)現(xiàn)
            這個(gè)功鞥.你可以同過方括號(hào)來指定策略,例如:

            int ret = call_function(
            L
            , "a_lua_function"
            , new complex_class()
            )[ adopt(_1) ];


            如果你想通過引用方式傳遞參數(shù),你必須用Boost.Ref來包裝一下.
            例如:

            int ret = call_function(L, "fun", boost::ref(val));


            如果你想給一個(gè)函數(shù)調(diào)用指定自己的錯(cuò)誤捕獲處理函數(shù)(error handler),可以參閱
            pcall errorfunc 章節(jié)的 set_pcall_callback .

            7.4 使用Lua協(xié)程

            為了使用Lua協(xié)程,你必須調(diào)用 lua_resume(),這就意味著你不能用先前介紹的函數(shù)
            call_function()來開始一個(gè)協(xié)程.你必須用這個(gè):

            template
            Ret resume_function(lua_State* L, const char* name, ...)
            template
            Ret resume_function(object const& obj, ...)

            和:

            template
            Ret resume(lua_State* L, ...)


            第一次開始一個(gè)協(xié)程的時(shí)候,你必須給它一個(gè)入口函數(shù). 當(dāng)一個(gè)協(xié)程返回(yield)的時(shí)候,
            resume_fucntion()調(diào)用的返回值是 lua_yield()的第一個(gè)傳入?yún)?shù).當(dāng)你想要繼續(xù)一個(gè)
            協(xié)程的時(shí)候,你只需要調(diào)用 resume() 在你的 lua_State() 上,因?yàn)樗呀?jīng)在執(zhí)行一個(gè)函數(shù)
            (即先前出入的入口函數(shù)),所以你不需要再次傳入函數(shù).resume()的傳入?yún)?shù)將作為Lua側(cè)的
            yield()調(diào)用的返回值.

            為了暫停(yielding)C++函數(shù),(不支持在C++側(cè)和Lua側(cè)傳送數(shù)據(jù)塊),你可以使用 yield 策略.

            接受 object 參數(shù)的resume_function()的重載版本要求對(duì)象必須是一個(gè)協(xié)程對(duì)象.(thread)

            lua_State* thread = lua_newthread(L);
            object fun = get_global(thread)["my_thread_fun"];
            resume_function(fun);



            8 綁定類到Lua

            為了注冊(cè)一個(gè)類,你可以用 class_ 類. 它的名字和C++關(guān)鍵字類似是為了比較直觀.它有一個(gè)重載
            過的成員函數(shù) def() .這個(gè)函數(shù)被用來注冊(cè)類的成員函數(shù),操作符,構(gòu)造器,枚舉和屬性.它將返回 this
            指針,從而方便你直接注冊(cè)更多的成員.

            讓我們開始一個(gè)簡單的例子.考慮下面的C++類:

            class testclass
            {
            public:
            testclass(const std::string& s): m_string(s) {}
            void print_string() { std::cout << m_string << "n"; }

            private:
            std::string m_string;
            };


            為了注冊(cè)這個(gè)類到Lua環(huán)境,可以像下面這樣寫(假設(shè)你使用了名空間):

            module(L)
            [
            class_("testclass")
            .def(constructor())
            .def("print_string", &testclass::print_string)
            ];


            這將注冊(cè) testclass 類以及接受一個(gè)string參數(shù)的構(gòu)造器以及一個(gè)成員叫print_string()的函數(shù).

            Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Rio
            > a = testclass('a string')
            > a:print_string()
            a string


            還可以注冊(cè)自由函數(shù)作為成員函數(shù).對(duì)這個(gè)自由函數(shù)的要求是,它必須接受該類的一個(gè)指針或常量指針或
            引用或常量引用作為函數(shù)的第一個(gè)參數(shù).該函數(shù)的剩下的參數(shù)將在Lua側(cè)可見,而對(duì)象指針將被賦值給第一個(gè)
            參數(shù).如果我們有如下的C++代碼:

            struct A
            {
            int a;
            };

            int plus(A* o, int v) { return o->a + v; }


            你可以注冊(cè) plus() 作為A的一個(gè)成員函數(shù),如下:


            plus() 現(xiàn)在能夠被作為A的一個(gè)接受一個(gè)int參數(shù)的成員函數(shù)來調(diào)用.如果對(duì)象指針(this指針)是const,
            這個(gè)函數(shù)也將表現(xiàn)的像一個(gè)常量成員函數(shù)那樣(它可以通過常量對(duì)象來調(diào)用).

            8.1 重載成員函數(shù)

            當(dāng)綁定超過一個(gè)以上的重載過的成員函數(shù)的時(shí)候,或只是綁定其中的一個(gè)的時(shí)候,你必須消除你傳遞給 def() 的
            成員函數(shù)指針的歧義.為此,你可以用普通C風(fēng)格的類型轉(zhuǎn)換來轉(zhuǎn)型匹配正確的重載函數(shù). 為此,你必須知道怎么去
            描述C++成員函數(shù)的類型.這里有一個(gè)簡短的教程(更多信息請(qǐng)查閱你的C++參考書):
            成員函數(shù)指著的語法如下:

            return-value (class-name::*)(arg1-type, arg2-type, ...)

            例如:

            struct A
            {
            void f(int);
            void f(int, int);
            };
            class_()
            .def("f", (void(A::*)(int))&A::f)


            A的第一個(gè)成員函數(shù)f(int)被綁定了,而第二個(gè)沒喲被綁定.

            8.2 屬性

            很容易注冊(cè)類的全局?jǐn)?shù)據(jù)成員.考慮如下的類:

            struct A
            {
            int a;
            };


            這個(gè)類可以這樣注冊(cè):


            這使得成員變量 A::a 獲得了讀寫訪問權(quán). 還可以注冊(cè)一個(gè)只讀的屬性:


            當(dāng)綁定成員是一個(gè)非原始數(shù)據(jù)類型的時(shí)候,自動(dòng)生成的 getter 函數(shù)將會(huì)返回一個(gè)它引用.
            這就允許你可以鏈?zhǔn)绞褂?. 操作符.例如,當(dāng)有一個(gè)結(jié)構(gòu)體包含另外一個(gè)結(jié)構(gòu)體的時(shí)候.如下:

            struct A { int m; };
            struct B { A a; };


            當(dāng)綁定B到Lua的時(shí)候,下面的表達(dá)式應(yīng)該可以工作:

            b = B()
            b.a.m = 1
            assert(b.a.m == 1)


            這要求 a 屬性必須返回一個(gè)A的引用, 而不是一個(gè)拷貝. 這樣,LuaBind將會(huì)自動(dòng)使用依賴策略來
            確保返回值依賴于它所在的對(duì)象.所以,如果返回的引用的生命長于該對(duì)象的所有的引用(這里是b).
            它將保持對(duì)象是激活的,從而避免出現(xiàn)懸掛指針.

            你還可以注冊(cè) getter 或者 setter 函數(shù)來使得它們看上去像一個(gè) public 的成員.考慮下面的類:

            class A
            {
            public:
            void set_a(int x) { a = x; }
            int get_a() const { return a; }

            private:
            int a;
            };


            可以這樣注冊(cè)成一個(gè)公共數(shù)據(jù)成員:


            這樣 set_a() 和 get_a() 將取代簡單的數(shù)據(jù)成員操作.如果你想使之只讀,你只需要省略最后一個(gè)參數(shù).
            請(qǐng)注意, get 函數(shù)必須是 const 的,否則不能通過編譯.

            8.3 枚舉

            如果你的類包含枚舉,你可以注冊(cè)它們到Lua. 注意,它們不是類型安全的,所有的枚舉在Lua側(cè)都是整型的,
            并且所有接受枚舉參數(shù)的函數(shù)都將接受任何整型.你可以像這樣注冊(cè)它們:


            在Lua側(cè),他們可以像數(shù)據(jù)成員那樣被操作,除了它們是只讀的而且屬于類本身而不是類的實(shí)例.

            Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Rio
            > print(A.my_enum)
            4
            > print(A.another_enum)
            6


            8.4 操作符

            為了綁定操作符,你需要包含頭文件 .
            注冊(cè)你的類的操作符的機(jī)制非常的簡單.你通過一個(gè)全局名字 luabind::self 來引用類自己,然后你就
            可以在def()調(diào)用里面直接用操作符表達(dá)式. 類如下:

            struct vec
            {
            vec operator+(int s);
            };


            可以這樣注冊(cè):

            module(L)
            [
            class_("vec")
            .def(self + int())
            ];


            不管你的 + 操作符是定義在類里面還是自由函數(shù)都可以工作.
            如果你的操作符是常量的(const)(或者,是一個(gè)自由函數(shù), 接受一個(gè)類的常量的引用)你必須用
            const_self 替代 self. 如下:

            module(L)
            [
            class_("vec")
            .def(const_self + int())
            ];


            支持如下操作符:

            + - * / == < <=


            這意味著,沒有"就地操作符"(in-place)(++ --). 相等操作符(==)有些敏銳;如果引用是相等的就不會(huì)
            被調(diào)用. 這意味著, 相等操作符的效率非常好.

            Lua不支持操作符包括: !=,>和<=.這是為什么你只能注冊(cè)上面那些操作符. 當(dāng)你調(diào)用這些操作符的時(shí)候,
            Lua會(huì)把調(diào)用轉(zhuǎn)換到支持的操作符上.(譯注:例如:==和!=有邏輯非得關(guān)系)

            在上面的示例中,操作數(shù)的類型是 int().如果操作數(shù)的類型是復(fù)雜類型,就不是那么簡單了,你需要用 other<>
            來包裝下.例如:
            為了注冊(cè)如下的類,我們不想用一個(gè)string的實(shí)例來注冊(cè)這個(gè)操作符.

            struct vec
            {
            vec operator+(std::string);
            };


            取而代之的是,我們用 other<> 包裝下,如下:

            module(L)
            [
            class_("vec")
            .def(self + other())
            ];


            注冊(cè)一個(gè)應(yīng)用程序操作符(函數(shù)調(diào)用):

            module(L)
            [
            class_("vec")
            .def( self(int()) )
            ];


            這里有個(gè)特殊的操作符.在Lua里,它叫做 __tostring,它不是一個(gè)真正的操作符.它是被用來轉(zhuǎn)換一個(gè)對(duì)象到
            string的標(biāo)準(zhǔn)Lua方法.如果你注冊(cè)之,可以通過Lua的標(biāo)準(zhǔn)函數(shù) tostring() 來轉(zhuǎn)換你的對(duì)象到一個(gè)string.

            為了在C++里實(shí)現(xiàn)這個(gè)操作符,你需要為 std::ostream 提供 operator<< .像這樣:

            class number {};
            std::ostream& operator<<(std::ostream&, number&);

            ...

            module(L)
            [
            class_("number")
            .def(tostring(self))
            ];



            8.5 嵌套作用域和靜態(tài)函數(shù)

            可以添加嵌套的作用域到一個(gè)類.當(dāng)你需要包裝一個(gè)嵌套類或者一個(gè)靜態(tài)函數(shù)的時(shí)候就會(huì)很有用.

            class_("foo")
            .def(constructor<>()
            .scope
            [
            class_("nested"),
            def("f", &f)
            ];


            在上面的例子里, f 將表現(xiàn)的像一個(gè)類 foo 的靜態(tài)函數(shù),而 類 nested 將表現(xiàn)的像類 foo 的嵌套類.

            還可以用同樣的語法添加名空間到類里面.


            8.6 繼承類

            如果你想要注冊(cè)一個(gè)繼承自其它類的類到Lua, 你可以指定一個(gè)模板參數(shù) bases<> 給 class_ 的構(gòu)造器.
            如下的繼承關(guān)系:

            struct A {};
            struct B : A {};


            可以這樣注冊(cè):

            module(L)
            [
            class_("A"),
            class_("B")
            ];


            如果你使用了多繼承,你可以指定多于一個(gè)的基類.如果 B 還繼承了類 C , 它可以這樣注冊(cè):

            module(L)
            [
            class_<B, bases >("B")
            ];

            注意,你可以省去 bases<> 當(dāng)你用的是單繼承的時(shí)候.

            注意

            如果你不指定類的繼承關(guān)系, LuaBind 將不能在相關(guān)的繼承類型間進(jìn)行隱式類型轉(zhuǎn)換.



            8.7 智能指針

            當(dāng)你注冊(cè)一個(gè)類的時(shí)候,你可以告訴 LuaBind 所有的該類的實(shí)例應(yīng)該被某種智能指針持有.(例如: boost::shared_ptr)
            你可通過把一個(gè) 持有器類型模板參數(shù) 給 class_ 類的構(gòu)造器來實(shí)現(xiàn)該功能.例如:

            module(L)
            [
            class_<A, boost::shared_ptr >("A")
            ];


            你還必須為你的智能指針提供兩個(gè)函數(shù).一個(gè)返回常量版本的智能指針類型(這里是: boost:shared_ptr< const A >).
            另一個(gè)函數(shù)要可以從智能指針萃取流指針(raw pointer). 之所以需要第一個(gè)函數(shù)是因?yàn)?LuaBind 允許
            非常量 -> 轉(zhuǎn)換在傳遞Lua值到C++的時(shí)候.之所以需要第二個(gè)函數(shù)是因?yàn)?當(dāng)Lua調(diào)用一個(gè)被智能指針持有
            的類的成員函數(shù)的時(shí)候,this 指針必須是一個(gè)流指針.還有一個(gè)原因是,從Lua轉(zhuǎn)換到C++的時(shí)候,需要實(shí)現(xiàn)
            智能指針到普通指針的轉(zhuǎn)換.看上去像這樣:

            namespace luabind {

            template
            T* get_pointer(boost::shared_ptr& p)
            {
            return p.get();
            }

            template
            boost::shared_ptr*
            get_const_holder(boost::shared_ptr*)
            {
            return 0;
            }
            }


            第二個(gè)函數(shù)只在編譯時(shí)用于映射 boost::shared_ptr到其常量版本 boost::shared_ptr.
            它從來不會(huì)被調(diào)用,所以返回值是無所謂的(返回值的類型才是關(guān)鍵).

            這個(gè)轉(zhuǎn)換將這樣工作(假定 B 是A的基類):
            從Lua到C++
            Source Target
            holder_type A*
            holder_type B*
            holder_type A const*
            holder_type B const*
            holder_type holder_type
            holder_type holder_type<A const>
            holder_type<A const> A const*
            holder_type<A const> B const*
            holder_type<A const> holder_type<A const

            從C++到Lua
            Source Target
            holder_type holder_type
            holder_type<A const> holder_type<A const>
            holder_type const& holder_type
            holder_type<A const> const& holder_type<A const>

            當(dāng)使用持有器類型的時(shí)候,知道指針是不是合法(例如:非空)是很有用的.例如,當(dāng)使用 std::auto_ptr 的時(shí)候,
            持有器通過一個(gè)參數(shù)傳遞給函數(shù)的時(shí)候?qū)?huì)變得無效. 為了這個(gè)目的,所有的對(duì)象實(shí)例都有一個(gè)成員叫: __ok.

            struct X {};
            void f(std::auto_ptr);

            module(L)
            [
            class_<X, std::auto_ptr >("X")
            .def(constructor<>()),

            def("f", &f)
            ];
            Lua 5.0  Copyright (C) 1994-2003 Tecgraf, PUC-Rio
            > a = X()
            > f(a)
            > print a.__ok
            false


            當(dāng)注冊(cè)一個(gè)繼承樹的時(shí)候,所有的實(shí)例被智能指針持有的地方,所有的類必須包含持有器類型.例如:

            module(L)
            [
            class_<base, boost::shared_ptr >("base")
            .def(constructor<>()),
            class_<derived, base, boost::shared_ptr >("base")
            .def(constructor<>())
            ];


            在內(nèi)部, LuaBind 將會(huì)做必要的轉(zhuǎn)換于萃取自持有器的流指針之上.

            8.8 拆分類注冊(cè)

            在某些情況下,可能需要分開注冊(cè)一個(gè)類在不同的編譯單元. 部分原因可能是節(jié)約重編譯時(shí)間,而某些編譯器的
            限制可能要求不得不分開注冊(cè)一個(gè)類.其實(shí)很簡單.考慮下面的示例代碼:

            void register_part1(class_& x)
            {
            x.def(/*...*/);
            }

            void register_part2(class_& x)
            {
            x.def(/*...*/);
            }

            void register_(lua_State* L)
            {
            class_ x("x");

            register_part1(x);
            register_part2(x);

            module(L) [ x ];
            }


            這里,類X被分兩步注冊(cè).兩個(gè)函數(shù) register_part register_part2 可能被放到不同的編譯單元里.

            關(guān)于分開注冊(cè)一個(gè)模塊的信息請(qǐng)參閱: 分開注冊(cè) 章節(jié).



            9 對(duì)象

            因?yàn)楹瘮?shù)必須能夠接受Lua值作為參數(shù),我們必須包裝之. 這個(gè)包裝被稱作
            luabind::object. 如果你注冊(cè)的函數(shù)
            接受一個(gè)對(duì)象,那它就可以匹配任何Lua值.為了使用它,你需要包含頭文件: .

            摘要

            class object
            {
            public:
            template
            object(lua_State*, T const& value);
            object(from_stack const&);
            object(object const&);
            object();

            ~object();

            lua_State* interpreter() const;
            void push() const;
            bool is_valid() const;
            operator safe_bool_type () const;

            template
            implementation-defined operator[](Key const&);

            template
            object& operator=(T const&);
            object& operator=(object const&);

            bool operator==(object const&) const;
            bool operator<(object const&) const;
            bool operator<=(object const&) const;
            bool operator>(object const&) const;
            bool operator>=(object const&) const;
            bool operator!=(object const&) const;

            template
            implementation-defined operator[](T const& key) const

            void swap(object&);

            implementation-defined operator()();

            template
            implementation-defined operator()(A0 const& a0);

            template
            implementation-defined operator()(A0 const& a0, A1 const& a1);

            /* ... */
            };


            當(dāng)你需要一個(gè)Lua對(duì)象的時(shí)候,你可以通過=操作符給它賦一個(gè)新值.當(dāng)你這么做的時(shí)候,default_policy
            會(huì)被用來轉(zhuǎn)換C++值到Lua. 如果你的 luabind::object 是一個(gè)table,你可以通過 []操作符或者迭代器
            來訪問它的成員.[]操作符的返回值是一個(gè)代理對(duì)象,這個(gè)對(duì)象可以用于讀寫表里的值(通過=操作符).

            注意,沒有辦法知道一個(gè)Lua對(duì)象是否可以索引化訪問( lua_gettable 不會(huì)失敗,要不成功,要不崩潰 ).
            這意味著,如果你在一個(gè)不可以索引化訪問的東西上進(jìn)行索引,你就只能靠自己了.Lua將會(huì)調(diào)用它的 panic()
            函數(shù).

            還有一些自由函數(shù)可以用來索引一張table,參閱 相關(guān)函數(shù) 章節(jié).

            那個(gè)接受 from_stack 對(duì)象作為參數(shù)的構(gòu)造器是用來初始化一個(gè)關(guān)聯(lián)Lua棧值的對(duì)象的. from_stack 類型
            有如下的構(gòu)造器:

            from_stack(lua_State* L, int index);


            index參數(shù)就是原始的Lua棧的索引,負(fù)值是從棧頂開始索引的.你可以這樣用:

            object o(from_stack(L, -1));


            這將會(huì)創(chuàng)建一個(gè) object的實(shí)例 o,并拷貝Lua棧頂?shù)膶?duì)象的值.

            interpreter() 函數(shù)返回保存object實(shí)例的Lua狀態(tài)機(jī).如果你想要直接用Lua函數(shù)操作object對(duì)象的實(shí)例,你
            可以通過調(diào)用 push() 來把它壓入Lua棧.

            ==操作符將會(huì)在操作數(shù)上調(diào)用 lua_equal()并返回它的結(jié)果.

            is_valid() 函數(shù)會(huì)告訴你object的實(shí)例是否已經(jīng)初始化過了.通過默認(rèn)構(gòu)造器來初始化的實(shí)例是非法的.要使之
            合法,你可以給其賦一個(gè)值.如果你想使一個(gè) object 不合法,最簡單的辦法就是給它賦一個(gè)非法的 object.

            operator safe_bool_type() 和 to is_valid() 是等價(jià)的.這意味著,下面的代碼片段是等價(jià)的:

            object o;
            // ...
            if (o)
            {
            // ...
            }

            ...

            object o;
            // ...
            if (o.is_valid())
            {
            // ...
            }


            應(yīng)用程序操作符() 將會(huì)像對(duì)待一個(gè)函數(shù)那樣來調(diào)用綁定的值. 你可以給它任何數(shù)量的參數(shù)
            (目前,
            default_policy 將被用于轉(zhuǎn)換 ).返回的對(duì)象將代表函數(shù)的返回值(當(dāng)前只支持一個(gè)返回值).該操作符
            可能會(huì)拋出
            luabind::error ,如果函數(shù)調(diào)用失敗.如果你想指定一個(gè)特殊的函數(shù)調(diào)用策略,你可以通過在函數(shù)
            調(diào)用時(shí)使用 []操作符來指定策略.像這樣:

            my_function_object(
            2
            , 8
            , new my_complex_structure(6)
            ) [ adopt(_3) ];


            這告訴 LuaBind 讓 Lua 接受所有權(quán)和負(fù)責(zé)傳入給lua函數(shù)的指針.

            重要的是當(dāng)Lua狀態(tài)機(jī)關(guān)閉的時(shí)候,所有的 object 的實(shí)例都會(huì)被析構(gòu).object實(shí)例會(huì)持有Lua狀態(tài)機(jī)的指針,并在
            自己析構(gòu)的時(shí)候釋放它的Lua對(duì)象.

            這里有一個(gè)函數(shù)怎樣使用 table 的例子:

            void my_function(object const& table)
            {
            if (type(table) == LUA_TTABLE)
            {
            table["time"] = std::clock();
            table["name"] = std::rand() < 500 ? "unusual" : "usual";

            std::cout << object_cast(table[5]) << "n";
            }
            }


            如果函數(shù)接受一個(gè)object作為參數(shù),那么任何Lua值都將匹配這個(gè)參數(shù).這就是為什么,我們必須保證入?yún)⑹且粋€(gè)table

            的原因.

            std::ostream& operator<<(std::ostream&, object const&);


            流操作符可以把object實(shí)例借由 boost::lexical_cast 轉(zhuǎn)換到string或者方便打印輸出.這將會(huì)使用Lua的string

            轉(zhuǎn)換函數(shù).如果你用 tostring 去轉(zhuǎn)換一個(gè)C++對(duì)象,對(duì)應(yīng)類型的流操作符將會(huì)被使用.

            9.1 迭代器

            有兩種迭代器. 普通迭代器將會(huì)使用對(duì)象的原方法(如果存在)來獲取值. 普通迭代器被稱為 luabind::iterator. 另一個(gè)

            迭代器被稱為 luabind::raw_iterator ,它將忽略原方法而直接給出表里的真實(shí)內(nèi)容. 它們具有相同的接口, 都實(shí)現(xiàn)了

            ForwardIterator 概念.大部分標(biāo)準(zhǔn)迭代器都有如下的成員和構(gòu)造器:

            class iterator
            {
            iterator();
            iterator(object const&);

            object key() const;

            standard iterator members
            };


             

             

            接受一個(gè) luabind::object 的構(gòu)造器實(shí)際上是一個(gè)用于操作 object 的模板.通過傳入一個(gè) object 給構(gòu)造器來構(gòu)造出

            一個(gè)指向 object 里的第一個(gè)元素的迭代器.

            缺省的構(gòu)造器將會(huì)初始化迭代器為一個(gè)指向最后一個(gè)元素的后面位置的迭代器.這可以用來測試是否抵達(dá)了序列的末端.


            迭代器的值類型是一個(gè)支持和 luabind::object 相同的操作的代理類型.這意味著,大部分情況下你可以當(dāng)它就是一個(gè)原始
            的 object 實(shí)例. 它們之間的不同之處在于,任何對(duì)代理的賦值操作都會(huì)導(dǎo)致值被插入到表中迭代器所指的位置.

            key() 成員返回迭代器用于索引表的鍵.

            一個(gè)迭代器的例子如下:

            for (iterator i(globals(L)["a"]), end; i != end; ++i)
            {
            *i = 1;
            }


            end 迭代器是一個(gè)缺省的指向序列末尾的迭代器.在這個(gè)例子里,我們簡單的迭代了表 a 里面所有的實(shí)體,并將之賦值為 1.


            9.2 相關(guān)函數(shù)

            這里介紹些用于 對(duì)象 和 表 操作的函數(shù).

            int type(object const&);


            這個(gè)函數(shù)將會(huì)返回lua類型索引.例如: . LUA_TNIL, LUA_TNUMBER 等.

            template
            void settable(object const& o, K const& key, T const& value);
            template
            object gettable(object const& o, K const& key);
            template
            void rawset(object const& o, K const& key, T const& value);
            template
            object rawget(object const& o, K const& key);


            這些函數(shù)是用來索引 table 用的. settable 和 gettable 函數(shù)分別翻譯調(diào)用到 lua_settable lua_gettable 函數(shù).
            這意味著,你可以在對(duì)象上使用索引操作符.

            rawset 和 rawget 將會(huì)翻譯調(diào)用到 lua_rawset 和 lua_rawget. 所以他們可以繞開任何原方法而給你表里實(shí)體的
            真實(shí)值.

            template
            T object_cast(object const&);
            template
            T object_cast(object const&, Policies);

            template
            boost::optional object_cast_nothrow(object const&);
            template
            boost::optional object_cast_nothrow(object const&, Policies);


            object_cast 函數(shù)轉(zhuǎn)型對(duì)象的值到C++值.你可以給這個(gè)從lua到C++的轉(zhuǎn)換提供一個(gè)轉(zhuǎn)換策略.如果轉(zhuǎn)型失敗,
            cast_failed 異常將被拋出. 如果你已經(jīng)定義了
            LUABIND_NO_ERROR_CHECKING (參閱 編譯選項(xiàng))宏,就不會(huì)
            進(jìn)行任何檢查,如果轉(zhuǎn)型非法,應(yīng)用程序?qū)?huì)徹底崩潰. 不拋出異常的版本會(huì)返回一個(gè)沒有初始化的
            boost::optional 對(duì)象,由此來指出轉(zhuǎn)型不能進(jìn)行.

            上面的函數(shù)的簽名確實(shí)是模板化的 object 參數(shù),但是這里你應(yīng)該只傳遞 object 對(duì)象.

            object globals(lua_State*);
            object registry(lua_State*);


             

             

            這些函數(shù)分別返回全局環(huán)境表和Lua注冊(cè)表.

            object newtable(lua_State*);


             

             

            這個(gè)函數(shù)創(chuàng)建一個(gè)新的 table 并以一個(gè) object 來返回它.




            10 在Lua里定義類

            作為一個(gè)附加功能,LuaBind還提供了一個(gè) Lua側(cè)OO系統(tǒng)來綁定C++函數(shù)和對(duì)象.

            class 'lua_testclass'

            function lua_testclass:__init(name)-- 譯注:這個(gè)風(fēng)格類似Python的OO語法
            self.name = name
            end

            function lua_testclass:print()
            print(self.name)
            end

            a = lua_testclass('example')
            a:print()


             

            在Lua類之間可以使用繼承:

            class 'derived' (lua_testclass)

            function derived:__init() super('derived name')
            end

            function derived:print()
            print('Derived:print() -> ')
            lua_testclass.print(self)-- 譯注:注意這里 : 和 . 的區(qū)別
            end


             

             

            這里的 super 關(guān)鍵字用來初始化基類.用戶必須在構(gòu)造器里面第一個(gè)調(diào)用 super.

            正如你在這個(gè)例子里看到的,你可以調(diào)用基類的成員函數(shù).你可以找到所有的基類成員,但是你必須把 this指針(self)

            做為函數(shù)的第一個(gè)參數(shù).

            10.1 在Lua里繼承

            你還可以從Lua側(cè)繼承一個(gè)C++類,并用Lua函數(shù)來覆寫虛函數(shù).為了實(shí)現(xiàn)這個(gè),我們必須為C++基類創(chuàng)建一個(gè)封裝類.

            當(dāng)我們實(shí)例化一個(gè)Lua類的時(shí)候,這個(gè)封裝類將持有Lua對(duì)象.

            class base
            {
            public:
            base(const char* s)
            { std::cout << s << "n"; }

            virtual void f(int a)
            { std::cout << "f(" << a << ")n"; }
            };

            struct base_wrapper : base, luabind::wrap_base
            {
            base_wrapper(const char* s)
            : base(s)
            {}

            virtual void f(int a)
            {
            call("f", a);
            }

            static void default_f(base* ptr, int a)
            {
            return ptr->base::f(a);
            }
            };

            ...

            module(L)
            [
            class_ ("base")
            .def(constructor())
            .def("f", &base::f, &base_wrapper::default_f)
            ];


             

             


            重要

            因?yàn)镸SVC6.5不支持成員函數(shù)的顯示模板參數(shù)化,作為成員函數(shù) call()的替代, 你可以調(diào)用自由函數(shù) call_member()并把 this指針作為第一個(gè)參數(shù)傳入該函數(shù).


             

             

            注意,如果你同時(shí)綁定 base 類 和 base類封裝,你必須把基類和基類的封裝一起作為模板參數(shù)提供給 class_

            (就像上面的例子中所做的一樣).你指定它們的順序并不重要.你必須還要從wrapper注冊(cè)靜態(tài)版本的和虛函數(shù)版

            本的封裝函數(shù),這是讓LuaBind實(shí)現(xiàn)動(dòng)態(tài)和靜態(tài)分派函數(shù)調(diào)用的必須.


            重要

            極其重要的是靜態(tài)(缺省)函數(shù)的簽名必須和虛函數(shù)一致.




            Linker Lin翻譯此文檔只為提供更多信息,轉(zhuǎn)載請(qǐng)保留 原文鏈接.

            posted on 2008-05-08 13:52 李陽 閱讀(3667) 評(píng)論(1)  編輯 收藏 引用 所屬分類: LUA

            評(píng)論:
            # re: LuaBind --最強(qiáng)大的Lua C++ Bind 2008-07-07 02:34 | Linker.Lin
            久久伊人精品青青草原高清| 精品蜜臀久久久久99网站| 久久久噜噜噜久久| 婷婷伊人久久大香线蕉AV | 久久亚洲AV无码精品色午夜| 久久午夜夜伦鲁鲁片免费无码影视| 国产成年无码久久久久毛片| 久久久久久精品免费看SSS| 久久久久久九九99精品| 婷婷综合久久中文字幕蜜桃三电影 | 久久超碰97人人做人人爱| 久久精品国产99国产精品导航 | 久久人妻少妇嫩草AV蜜桃| 观看 国产综合久久久久鬼色 欧美 亚洲 一区二区| 无码任你躁久久久久久| 要久久爱在线免费观看| 久久精品国产清自在天天线 | 久久精品人人做人人爽电影蜜月| 久久99精品国产99久久6| 伊人久久大香线蕉无码麻豆| 久久久久国产精品熟女影院| 欧美一级久久久久久久大片 | 香蕉久久AⅤ一区二区三区| 色综合久久中文字幕无码| 久久夜色tv网站| 一本一本久久a久久综合精品蜜桃 一本一道久久综合狠狠老 | 亚洲国产精品久久久久网站 | 亚洲欧美精品伊人久久| 少妇久久久久久久久久| 伊人久久久AV老熟妇色| 一本色道久久99一综合| 久久久久久av无码免费看大片 | 色综合久久综合中文综合网| 精品久久久久久无码不卡| 伊人久久综合成人网| 91久久精品电影| 青青青伊人色综合久久| 久久综合伊人77777| 色综合久久天天综合| 人人狠狠综合久久88成人| 久久精品国产精品青草app|