内容
SDLはC言語ベースのライブラリであり、C++のモダンな諸機能には対応していません。そんな中で、ラムダ式やクラスのメンバ関数を用いる方法についての備忘録です。
まずはSDL_Threadの定義
SDL_Threadのスレッド生成関数は以下のように定義されています。
SDL_Thread* SDL_CreateThread(SDL_ThreadFunction fn,
const char* name,
void* data)
この引数について、Wikiではfnはスレッドで実行する関数、nameはスレッド名、dataは関数fnに渡す引数であると説明されています。( https://wiki.libsdl.org/SDL_CreateThread )
また、SDL_thread.hでは、第一引数の型SDL_ThreadFunction
は、
typedef int (SDLCALL * SDL_ThreadFunction) (void *data);
として定義されています。( https://www.libsdl.org/tmp/SDL/include/SDL_thread.h )
なお、ここで出てきているSDLCALLは、__cdecl
や_System
としてDEFINEマクロで定義されている値です。
つまり、void*
を引数に取りint
を返す関数のポインタであれば、SDL_CreateThread
の第一引数として渡すことが可能になります。
ラムダ式の扱い方
キャプチャリストが空であるラムダ式は、引数と返り値の型が同じ関数ポインタに暗黙的に変換することが可能です。( https://riptutorial.com/ja/cplusplus/example/1970/関数ポインタへの変換 )
そのため、キャプチャリストが空ならば、単にvoid*
を引数に取りint
を返すようにさえすれば、ラムダ式はそのまま渡すことが可能ということになります。キャプチャリストは使えませんが、SDL_CreateThread
の第三引数で引数を渡すことができるので、それによって困ることはあまりないでしょう。
万一、どうしても必要になった場合は、ラムダ式を実行するコールバック関数を別に定義して使ってください。(参考:https://qiita.com/studiork/items/2d2951542d79cf94fb84 )
メンバ関数の扱い方
皆さんご存知の通り、メンバ関数ポインタは普通の関数ポインタとは別物になるので、ラムダ式の場合と違って、そのまま渡すというわけには行きません。オブジェクトの情報を別で引数として受け取って、引数の情報を使ってコールバック関数内で呼び出すというワンクッションが必要になります。
class Foo{
public:
int do_something();
}
Foo obj;
SDL_CreateThread([](void *arg)->int{
Foo *p_obj=reinterpret_cast<Foo*>(arg);
return p_obj->do_something();
//return 0; //do_something()の戻り値がintでないとき
}, "ThreadName", &obj);
多くの箇所で同様の処理を行う場合は、すべての場所でラムダ式を書くのは煩雑なので、同様の処理をテンプレート関数で書いて使う方が楽かもしれません。下の参考サイトは、そちらのアプローチをとっているので、必要に応じて参考にしてください。
(参考:https://kazuhooku.hatenadiary.org/entry/20110126/1296031454 )
あとがき
この記事は古い下書きをそのまま公開しています。不足点等ある可能性がありますので、周辺情報の確認の上でご利用ください。また、もしも誤りや説明不足な点などありましたら、ぜひコメント頂ければと思います。