現在、私は異なる呼び出し規約(__stdcall、__cdecl、__fastcallなど)のためのファンクタ(呼び出し可能なタイプ)を構築しています。正しいパラメータが指定されているように私がいる限り任意の__stdcall関数を呼び出すことが可能である__stdcall呼び出し規約のラッパーを構築している現時点で異なる呼び出し規約を持つ呼び出し可能オブジェクト
void __stdcall foo(int arg)
{
std::printf("arg: %i\n", arg);
}
int main(int, char**)
{
Function<void, int> v{foo};
v(1337);
return EXIT_SUCCESS;
}
:ラッパーで、私はこのような何かを行うことができるでしょうそして、正しい引数が渡されたクラスは、次のようになります。それに
template <typename ReturnT, typename... Args>
class Function
{
// NOTE: This version of my callable types
// only supports the __stdcall calling
// convention. I need support for __cdecl,
// __fastcall and also __thiscall.
using return_t = ReturnT;
using callable_t = return_t(__stdcall*)(Args...);
private:
callable_t mCallable;
public:
template <typename FuncT>
Function(FuncT const &func) :
mCallable(func)
{
;
}
void operator()(Args&&... args)
{
mCallable(std::forward<Args>(args)...);
}
};
手に、私は他のラッパーを構築することを決めたが、私は、コードの同じ部分を入力し、内部の呼び出し規約を変更することを考え出しcallable_tの宣言を使用することは、必要以上に多くの作業になります。だから私は約4種類の呼び出し可能な型(各呼び出し規約のために)を構築する方法を見出したいが、それを行う方法を見つけることができなかった。
これまでのところ、私はこのような非型テンプレートパラメータとして列挙型を使用しようとしました:
template <CallingConvention Call, typename ReturnT, typename... ArgsT>
class Function
{
// ...
};
しかし、私は、Callオブジェクトの型を反復処理し、必要な型を確立する方法がわからない(I std :: is_same/std :: enable_ifを利用しようとしましたが、それはデッドエンドでした)。私はまた、このようなコードをテンプレートの特殊化を試してみました:
struct StdcallT { ; };
struct CdeclT { ; };
struct FastcallT { ; };
template <typename CallT>
struct BaseT { };
template <> struct BaseT<StdcallT> { using CallableT = void(__stdcall*)(); };
template <> struct BaseT<CdeclT> { using CallableT = void(__cdecl*)(); };
template <> struct BaseT<FastcallT> { using CallableT = void(__fastcall*)(); };
template <typename CallT>
class Function
{
using CallableT = typename BaseT<CallT>::CallableT;
};
しかし、私は残りの引数(+パラメータ、戻り値の型)のことを考えていなかったので、これはあまりにも動作することはできません。
とにかく私は何ができるのですか?そのいくつかの良い選択肢があった場合、私は思っていた作業溶液のように見える
template <CallingConvention Call, typename ReturnT, typename... ArgsT>
class Function
{
void operator()(ArgsT&&... args)
{
switch(Call)
{
case CallingConvention::Cdecl:
// Call a __cdecl version
break;
case CallingConvention::Stdcall:
// Call an __stdcall version
break;
// And so on...
}
}
};
そして、これにもかかわらず:私は考えている一つの方法は、非型パラメータにスイッチを行うと、このように正しいものを呼び出しています私は考えていない。
アイデア?
なぜホイールを改造するのですか? 'std :: function'は、あなたが指定した引数で呼び出し可能である限り、呼び出し規約にかかわらず、すでに関数ポインタまたは関数子を格納することができます。それはあなたのためには機能しないのでしょうか、それともあなたのカスタム実装を始めるのにいくつかの具体的な欠点がありますか? – hvd
@hvd "glCreateProgram"や "glCreateShader"のようなstd :: unordered_mapの文字列をopengl32.dllからシンボルアドレスにロードしたとします。 args/returnsがない場合はvoidを使用し、バイナリ互換性があるのでargs/no argsの場合はstd :: tupleを使用するテンプレート関数function_cast を作成したいとします。 std:functionはstdcallでは機能しません。したがって、コンベンション呼び出しの呼び出しを切り替えるためのダミー呼び出し規約では、ランタイムが必要です。 –
Dmitry
@Dmitry "std:関数はstdcallで機能しません" - GCC(GCC 5まで)の古いバージョンは、名前のマングリングで呼び出し規約を無視し、リンカエラーを引き起こしましたが、これは2015年中頃に修正されました。少なくともそのコンパイラ以降、デフォルト以外の呼び出し規約の 'std :: function'に問題があります。他のコンパイラも同じように動作するはずです*。もしそうでなければ、それがどれであるかについての詳細を教えてもらえますか? – hvd