「luabind::nil」が標準で使えなかった話 | FrorpiaDiscSoftware 制作ブログ

FrorpiaDiscSoftware 制作ブログ

FrorpiaDiscSoftwareの管理人「ノウネム」の趣味やHP公開用ソフトウェアなどの制作ブログ。

どうも。お久しぶりです。
さて、今日はC++のluabindについての記事になります。
luabindについては「こちら」をご覧ください。

 

実は先ほどまでluabindと格闘しておりました。orz
正確には「luabind::nil」と格闘してました。

 

――というのも、Luaのnilについて、「Lua側から取得した結果、nilでした。」
――というのは取れるが、C++側から任意にnilを設定する事が出来ません。
Google先生に聞いて、色々と調べてみましたが、記事らしい記事を見つけられず、半ば諦めかけていました。

 

とりあえず、luabind名前空間に何か無いか漁っていた所、「nil」という変数があるのを見つけたので、適当に以下のコードで「luabind::object」にセットするよう書いたのですが・・・

 


#include <lua.hpp>
#include <luabind/luabind.hpp>

lua_State*       test_state = luaL_newstate();
luabind::object test_obj1;

luaL_openlibs(test_state);
luabind::open(test_state);

test_obj1 = luabind::object(test_state,luabind::nil);//nil代入テスト
if ( luabind::type(test_obj1) == LUA_TNIL ) { OutputDebugString("nilですよ!"); }

test_obj1 = luabind::object();
lua_close(test_state);//Luaを閉じる。
test_state = NULL;//念のため。


 

ビルド後、実行すると「nil代入テスト」の行でstd::runtime_errorになってしまいました。
停止行付近にあった、std::runtime_errorに渡しているエラー文字列を確認した所、「未登録のクラスを使用しようとしています」書かれており、「luabind::nil」自体が「luabind::detail::nil_type」構造体なのですが、どうも、luabind側で対応していないようです。(馬鹿なの?)

 

結局、色々調べてluabind内で使用している、テンプレートクラス「luabind::default_converter」を追加定義すればいけそうだったので、
以下のようなテンプレートの追加オーバーロード定義を行いました。

 


【NilConverter.h】


#ifndef INCLUDE_20190310_A655SUSXT4JY
#define INCLUDE_20190310_A655SUSXT4JY

#include <lua.hpp>
#include <luabind/luabind.hpp>

namespace luabind{
    
    template <>
    struct default_converter    <luabind::detail::nil_type>
    :      native_converter_base<luabind::detail::nil_type>{
        
        static int compute_score( lua_State* L , int index ) {
            switch ( lua_type( L , index ) ) {
                case LUA_TNIL:
                    return 0;//対応する型の場合は「0」を返せば良いっぽい。
                default:
                    return -1;//未対応の型は「-1」にするっぽい。
            }
        }
        
        luabind::detail::nil_type from( lua_State* L , int index ) {
            return luabind::nil;
        }
        
        void to( lua_State* L , luabind::detail::nil_type const& value ) {
            lua_pushnil(L);
        }
        
    };
    
    template <> struct default_converter<luabind::detail::nil_type const > : default_converter<luabind::detail::nil_type>{};
    template <> struct default_converter<luabind::detail::nil_type const&> : default_converter<luabind::detail::nil_type>{};
   
}

#endif//INCLUDE_20190310_A655SUSXT4JY


 

これを最初にランタイムエラーになってしまったコードに対して、
インクルードするようにします。

 


#include "NilConverter.h"

lua_State*       test_state = luaL_newstate();
luabind::object test_obj1;

luaL_openlibs(test_state);
luabind::open(test_state);

test_obj1 = luabind::object(test_state,luabind::nil);//nil代入テスト
if ( luabind::type(test_obj1) == LUA_TNIL ) { OutputDebugString("nilですよ!"); }

test_obj1 = luabind::object();
lua_close(test_state);//Luaを閉じる。
test_state = NULL;//念のため。


※変更箇所は表記になってます。

 

後はこれをもう一度ビルドして実行するだけです。
実際に実行してみた所、ランタイムエラーにならず、「出力」ウィンドウに「nilですよ!」が表示されました!

 

とはいえ、まさかluabind内に標準定義されている物が使えないとは思いもよらなかったです。(もしかしたら違う使い方を想定していたのかも知れませんが。)

 

ともあれ、これでLuaとC++双方でnilのやり取りが出来るようになったので、よしとしましょう!(`・ω・´)b