Luaから無名関数を貰ってC++側で実行する

もしかしたらできるんじゃないの?と思ったらやはりできたのでメモしておきます。
Luaさんに処理の一部分を書いて貰いたい場合、名前が必要な通常の関数はめんどいです。その名前が無きゃ呼び出すのめんどそうです。後名前が干渉してどうこうとかありそうですね。
Luabindは関数もテーブルも、Lua内のデータはすべてluabind::objectという型にしてしまって、luabind::object_castで任意の型にキャストする、という使い方ができます。

本題ですが、C++側からLuaのある無名関数を返却する関数を実行し無名関数を受け取り、それをC++側実行することができるんじゃないかと思って試しに書いた所、普通にできましたので以下ソース。

// C++
#include <lua.hpp>
#include <lualib.h>
#include <luabind/luabind.hpp>

int main()
{
    ::lua_State* L = lua_open();
    ::luaL_openlibs(L);
    ::luabind::open(L);

    if( ::luaL_loadfile(L,"test.lua") == 0 )
    {
        ::lua_pcall(L,0,0,0);

        // Luabindの関数呼び出しでLua側で定義された関数を受け取る
        ::luabind::object const func = ::luabind::call_function<::luabind::object>(L,"get_function");

        // 中身が関数である事を確認して、呼び出す
        assert(::luabind::type(func) == LUA_TFUNCTION);
        ::luabind::call_function<void>(func,2,5,"krustf");
    }

    ::lua_close(L);
}
-- Lua
function get_function()
    return
        -- 数値データ2つと文字列1つを受け取る関数を返却
        function( x, y, name )
            print( string.format("%d + %d = %d",x,y,x+y) )
            print( string.format("Hello, %s !!",name) )
        end
end
// 実行結果
2 + 5 = 7
Hello, krustf !!

注意点は2つ。関数を呼び出す時は戻り値の指定をluabind::object型にしてLua側の関数を受け取れるようにすること、戻り値のluabind::objectデータの中身が関数以外であることもあるのでちゃんと中身が関数であるのかのチェックも忘れないこと。
それさえ守ればこんな感じでできるので、あるクラスのコンストラクタLua側で定義されたイベント関数を受け取れますね。luabind::objectの中身がなんであるかをチェックするにはluabind::type関数を使うと簡単に分かります。戻り値はLUA_TFUNCION, LUA_TNUMBERなどです。