Проблемы с соглашением о вызовах Luabind

У меня проблема с Luabind, которую я не знаю, как исправить без чрезмерно упрощенного решения.

Luabind, похоже, разрешает привязку только к функциям с использованием __cdecl соглашения о вызовах. В моем текущем проекте вся функциональность, доступная для расширений / плагинов, представлена ​​с помощью __stdcall. Это лишает меня возможности напрямую связывать открытые объекты, и вместо этого мне приходится создавать оболочки для этих объектов. Это было бы хорошо, но есть много объектов, которые нужно обернуть.

Например, объект может выглядеть так:

struct IObject
{
    void __stdcall SomeFunc1( void );
    void __stdcall SomeFunc2( const char* );
};

struct IObjectContainer
{
    IObject* __stdcall GetObject( int );
    IObject* __stdcall GetObject( const char* );
};

struct IObjectCore
{
    IObjectContainer* __stdcall GetObjectContainer();
};

В настоящее время у меня нет возможности изменить соглашение о вызовах всего проекта, поэтому я смотрю, есть ли у кого-нибудь решение, возможно, исправление Luabind для работы с __stdcall функциями. Я не лучший специалист в области шаблонов и повышения качества, поэтому я лично не уверен, с чего начать пытаться добавить возможность использования __stdcall функций.

Для справки я использую:

  • Lua 5.1.4
  • Луабинд 0.9.1
  • VS2010

И Lua, и Luabind являются свежими версиями их rev. (Не использую Lua 5.2 по причинам ограничения проекта, но если есть __stdcall исправление для 5.2 / Luabind, я с радостью воспользуюсь и этим.)

Я смог найти исправление только для очень старой версии Luabind, чтобы сделать это, но патч, плавающий в сети, все еще не соответствует текущему коду Luabind вообще.

Если вам нужна другая информация, не стесняйтесь спрашивать.


person atom0s    schedule 08.11.2012    source источник
comment
Вы можете обернуть эти объекты в другое соглашение о вызовах и связать их   -  person Dmitry Ledentsov    schedule 08.11.2012
comment
Я знаю, я уже говорил об этом в посте. Я четко заявил, что стараюсь этого не делать.   -  person atom0s    schedule 09.11.2012
comment
Извините, что пропустил это. Впрочем, на привязки все равно придется потратить время ...   -  person Dmitry Ledentsov    schedule 09.11.2012
comment
ммм .. ты смотрел мое решение?   -  person Patryk Czachurski    schedule 15.06.2014
comment
Однако мне больше не нужно решение этой проблемы, спасибо.   -  person atom0s    schedule 15.06.2014


Ответы (2)


К сожалению, из-за бездействия и отсутствия дальнейших ответов от дополнительных поисков я поговорил с разработчиком проекта и лишил весь проект __stdcall. Итак, привязки теперь работают нормально через __cdecl. Не тот маршрут, по которому я хотел пойти, но сейчас все идет по плану.

person atom0s    schedule 22.11.2012

Я столкнулся с той же проблемой при привязке OpenGL (с функциями GLEW) к Lua и решил ее, используя вариативные шаблоны.

Теперь, если функция глобальная и вы знаете ее адрес во время компиляции, вы можете хорошо справиться с чем-то вроде этого:

template<typename Signature>
struct wrap_known;

template<typename Ret, typename... Args>
struct wrap_known<Ret __stdcall (Args...)> {
    template <Ret __stdcall functor(Args...)>
    static Ret invoke(Args... arguments) {
        return functor(arguments...);
    }
};

// I know using macro is generally a bad idea but it's just shorter
#define wrap(f) wrap_known<decltype(f)>::invoke<f>

а затем при привязке используйте макрос следующим образом:

luabind::def("Clear", wrap(glClear)),
luabind::def("Vertex4f", wrap(glVertex4f))

Однако в вашем случае у нас есть несколько функций-членов, а не глобальные переменные, как указано выше. Вот код для обертывания функций-членов соглашением о вызовах __stdcall:

template<typename Signature>
struct wrap_mem;

template<typename Sub, typename Ret, typename... Args>
struct wrap_mem<Ret(__stdcall Sub::*) (Args...)> {

    template <Ret(__stdcall Sub::*functor) (Args...)>
    static Ret invoke(Sub* subject, Args... arguments) {
        return (subject->*functor)(arguments...);
    }
};

#define wrap_member(f) wrap_mem<decltype(f)>::invoke<f>

Используйте это так:

struct A {
    int __stdcall my_method(double b) {
        return 2;
    }
};

// ...
luabind::class_<A>("A")
.def("my_method", wrap_member(&A::my_method))

Однако иногда вам не повезло узнать адрес функции во время компиляции, например, это происходит с GLEW. Для таких функций, как glUniform * f, glGetUniformLocation, макрос "wrap" не будет работать, поэтому я сделал другую версию для обертывания функций, известных во время выполнения:

template<typename Signature>
struct wrap_unknown;

template<typename Ret, typename... Args>
struct wrap_unknown<Ret (__stdcall*) (Args...)> {
    template <Ret (__stdcall** functor)(Args...)>
    static Ret invoke(Args... arguments) {
        return (**functor)(arguments...);
    }
};

#define wrap_ptr(f) wrap_unknown<decltype(f)>::invoke<&f>

(если приведенный выше код пугает вас, на самом деле это хороший знак)

Теперь вы можете привязать функции GLEW следующим образом:

luabind::def("Uniform4f", wrap_ptr(glUniform4f)),
luabind::def("GetUniformLocation", wrap_ptr(glGetUniformLocation))

Только не просите меня написать другую версию для привязки указателей к членам, известным во время выполнения :)

Если вы по какой-то причине не хотите использовать C ++ 11, здесь вы можете узнать, как для передачи аргументов функции и возвращаемого значения в качестве параметров шаблона в C ++ 03.

person Patryk Czachurski    schedule 16.01.2014