W tej chwili buduję funktory (typy wywoływalne) dla różnych konwencji wywoływania (__stdcall, __cdecl, __fastcall itd.). Z owijarki będę w stanie zrobić coś takiego:Podlegające obiekty z różnymi konwencjami wywoływania
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;
}
W tej chwili zbudowali otoczka do __stdcall wywołującego konwencji, która jest w stanie wywołać dowolną funkcję __stdcall ile poprawne parametry są określone i poprawne argumenty są przekazywane w klasie wygląda następująco:.
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)...);
}
};
Mając to na rękę postanowiłem zbudować inne owijarki ale pomyślałem, że pisanie na ten sam kawałek kodu i zmieniając konwencję telefonicznej wewnątrz deklaracja użycia dla callable_t to więcej pracy niż potrzeba. Tak więc chciałem znaleźć sposób na zbudowanie około 4 wariantów typów wywoływalnych (dla każdej konwencji wywoływania), ale nie mogłem znaleźć sposobu na zrobienie tego.
Do tej pory starałem się używać enum jako parametr szablonu non typu jak ten:
template <CallingConvention Call, typename ReturnT, typename... ArgsT>
class Function
{
// ...
};
Ale nie wiem, jak iteracyjne typ obiektu telefonu rozmowy i ustalenia wymaganego typu (I próbowałem używać std :: is_same/std :: enable_if ale to był ślepy zaułek). Próbowałem też specjalizację szablonu z kodem tak:
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;
};
Ale nie myślał o resztę argumentów (typ zwrotny + parametry), więc to nie może pracować zbyt.
Tak czy inaczej masz jakieś pomysły, co mogę zrobić? Jedną z metod, które mam na myśli robi przełącznik na parametr typu non-i nazywając poprawny takiego:
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...
}
}
};
a mimo to wygląda jak roztworu roboczego Zastanawiałem się, czy nie było kilka dobrych alternatyw, które Nie myślę o tym.
Wszelkie pomysły?
Po co odnawiać koło? 'std :: function' powinno już być w stanie przechowywać dowolny wskaźnik funkcyjny lub funktor, niezależnie od konwencji wywoływania, o ile można go wywoływać z podanymi argumentami. Czy to nie działa dla Ciebie, czy ma jakieś konkretne wady, które sprawiły, że zaczynasz od niestandardowej implementacji? – hvd
@hvd załóżmy, że masz std :: unordered_map łańcuchy mapujące takie jak "glCreateProgram" i "glCreateShader" załadowane z opengl32.dll na ich adresy symboli. Chcesz utworzyć szablonową funkcję function_cast , które użyjesz void dla żadnych args/zwraca i std :: tuple dla args/no args, ponieważ są one kompatybilne binarnie. w obecnej postaci, std: funkcja nie działa dla stdcall, więc jeśli jest to wymagane, wymagana jest kontrola w przypadku jakiejś fałszywej konwencji wywołującej, w oparciu o którą przełączasz wywoływanie konwencji konwencji. –
Dmitry
@Dmitry "std: funkcja nie działa dla stdcall" - Starsze wersje GCC (do GCC 5) zignorowały konwencję wywołującą w manglingu nazw, powodując błędy linkera, ale zostało to naprawione w połowie 2015 r., I nie powinno być problemami z 'std :: function' dla niekonwencjonalnych konwencji wywoływania od tego czasu przynajmniej w tym kompilatorze. Inne kompilatory * powinny * działać w ten sam sposób. Jeśli nie, czy możesz podać szczegółowe informacje na temat tego, który jest? – hvd