Хороший вопрос. У меня было какое-то смутное представление о том, как luabind делает то, что делает, но я не знал достаточно, чтобы ответить полностью и точно. Вооружившись IDE и отладчиком, я начал разбирать следующую очень простую часть:
struct C
{
int i;
int f(int x, const char* s)
};
lua_State* L = luaL_newstate();
open(L);
module(L)
[
class_<C>("C")
.def_readwrite("index", &C::i)
.def("f", &C::f)
];
Первое, что следует отметить, это то, что L
часто передается в luabind, вызов open
создает несколько глобальных переменных в состоянии Lua: __luabind_classes
типа userdata и две функции class
и * 1008. *. Luabind, похоже, не использует глобальные переменные - все, что ему нужно, сохраняется в среде lua.
Теперь мы получаем module(L)[...]
. Оригинальный код - лучшее объяснение, сначала вот module
:
inline module_ module(lua_State* L, char const* name = 0)
{
return module_(L, name);
}
Достаточно просто, вот module_
:
class LUABIND_API module_
{
public:
module_(lua_State* L_, char const* name);
void operator[](scope s);
private:
lua_State* m_state;
char const* m_name;
};
Итак, наша маленькая программа вызывает оператор [] для класса module_
с некоторыми определениями (это параметр scope
), но класс module_
знает, в каком состоянии Lua работать. Класс scope
также интересен (некоторые части опущены, а некоторые немного упрощены):
struct LUABIND_API scope
{
//...
explicit scope(detail::registration* reg);
scope& operator,(scope s);
void register_(lua_State* L) const;
private:
detail::registration* m_chain;
};
scope
строит связанный список detail::registration
узлов, этот список получен с использованием operator,
. Так, когда кто-то делает module(L) [class_<...>..., class_<...>...]
, class_
, который наследует от scope
, инициализирует свою базу с экземпляром detail::registration
, то оператор запятой scope
создает связанный список всех регистраций, это передается в module_::operator[]
который вызывает scope::register_
, который, в свою очередь, перечисляет цепочку и вызывает register_
для всех этих detail::registration
объектов. lua_State
всегда передается в register_
.
Уф. Теперь давайте посмотрим, что происходит, когда кто-то делает class_<C>("C").def("f", &C::f)
. Это создает экземпляр class_<C>
с определенным именем, которое входит в член detail::registration
в class_
. Вызов метода class_::def
записывает в reg-структуру и еще много чего, но вот очень интересная строка в цепочке вызовов от def
:
object fn = make_function(
L, f, deduce_signature(f, (Class*)0), policies);
Ооо, deduce_signature
, я действительно хотел это увидеть. Теперь я хочу это увидеть, но способ, которым он работает, заключается в следующем: посредством темного колдовства препроцессора с помощью boost (BOOST_PP_ITERATE
и некоторых других утилит) генерируется следующее для каждого N между единицей и LUABIND_MAX_ARITY:
template <class R, class T, class A1, classA2, ..., classAN>
boost::mpl::vectorN_PLUS_2<R, T, A1, A2, ..., AN> // type of return value
deduce_signature(R(T::*)(A1, A2, ..., AN))
{
return boost::mpl::vectorN_PLUS_2<R, T, A1, A2, ..., AN>()
}
Опять же, такая функция генерируется для всех N от 1 до LUABIND_MAX_ARITY, которая по умолчанию равна 10. Существует несколько перегрузок для обработки методов const, виртуальных упаковщиков и свободных функций и т. Д., Что означает, что около 50 deduce_signature
функций заканчиваются в ваших источниках сразу после препроцессора и до начала компиляции. Отсюда задача компилятора выбрать правильную перегрузку deduce_signature
для функций, которые вы передаете в def
, и это вернет правильный тип boost::mpl::vectorX
. Оттуда make_function
может делать все что угодно - у него есть список типов параметров [время компиляции], и с помощью некоторой дополнительной магии шаблонов они подсчитываются, преобразуются в значения Lua и из них и так далее.
Здесь я остановлюсь. Расследование основано на Luabind 0.8.1. Не стесняйтесь просматривать / отлаживать код Luabind для получения дополнительных ответов - это займет некоторое время, но это не так сложно после того, как вы привыкнете к стилю :) Удачи.
TL; DR: Магия ... черная магия