SWIG を使用して C++ コードを Lua にバインドしています。これまでのところ問題ないように見えますが、Lua 内から単一のユーザーデータを「チート」して拡張し、カスタム フィールドやメソッドなどを追加する必要があります。
SWIG のディレクティブ内で作業しているときに、それを達成する方法が見つかりません。ラッパー コードのどこでマジックが行われるかはわかっていますが、__index と __newindex がどのように機能するかは完全にはわかりません。また、SWIG は __setitem と __getitem を使用しており、「/* NEW: __setitem() fn を検索します。これはユーザーが提供する set fn */ です」とコメントされています。これが何を意味するのかもわかりません。最後に、私の環境では、各ビルドの前に SWIG ディレクティブを C++ ラッパーにバインドするスクリプトが自動的に呼び出されるため、再コンパイルまたは Lua バインディングの追加を選択した場合、後でソースを変更するのは非常に面倒です。
これまでのところ、私の唯一の結論は、この機能が文書化されている toLua++ を使用することです。多くの移行作業を避けるのを手伝ってください!
編集: 5.2 で「lua_setuservalue」API 呼び出しも見つかりました。便利なようですが、すべての SWIG バインディング コードのどこで呼び出すかわかりません。
編集:物事を片付けるには:
C関数を持ってオブジェクトを作成します
SoundObj *loadSound(const char *name)
{
return g_audio->loadSound(name); // Returns SoundObj pointer
}
この関数は、そのプロトタイプを *.i swig 定義に含めることによって、SWIG によってバインドされます。
Lua では、次のようなコードを記述します。
sound = audio.loadSound("beep.mp3")
sound.scale = 0.2
sound:play()
編集:前進!Scholii の指示に従い、次の Lua コードを書きました。ここで、「ground」はバインドされた C++ コードを使用して以前に取得されたユーザーデータです。コードは __index と __newindex の swig のバージョンを格納し、次に別の ("_other") テーブルを最初にクエリするこれらの関数を再作成します。
ここでの私の現在の問題は、「_other」テーブルに格納された新しい値が、そのタイプのすべてのユーザーデータ オブジェクト間で共有されることです。つまり、ground.nameFoo = "ha!" の場合、他のすべてのオブジェクトには "ha!" を格納する nameFoo フィールドがあります。これを修正するにはどうすればよいですか?
mt = getmetatable(ground)
mt._other = {}
mt.__oldindex = mt.__index
mt.__oldnewindex = mt.__newindex
mt.__index = function(tbl, key)
if mt.__oldindex(tbl, key) == nil then
if mt._other[key] ~= nil then
return mt._other[key]
end
else
return mt.__oldindex(tbl, key)
end
end
mt.__newindex = function(tbl, key, val)
if mt.__oldnewindex(tbl, key, val) == nil then
mt._other[key] = val
end
end
編集: この回答からソリューションを実装しました: Add members dynamic to a class using Lua + SWIG
問題は、オブジェクト タイプがユーザーデータではなく、テーブルになっていることです。つまり、ユーザーデータを引数として取る他のバインドされた C++ 関数に引数として有機的に渡すことができなくなりました。これに対する解決策はありますか?そして、ユーザーデータ オブジェクトを返すすべての関数に対してこれを行う必要があります。