Open alextrevisan opened 10 years ago
Can you provide a simple test case demonstrating what you would want and the functionality you expect?
here a simple test case
#include <iostream>
#include <selene.h>
class SceneManager
{
public:
virtual int GetX() = 0;
};
class Octree: public SceneManager {
public:
int x;
Octree() {
x = 0;
}
int GetX() {
return x;
}
};
class Root {
public:
int x;
Root(int num) { x = num; printf("created BAR\n"); }
void SetX(int x2) {
x = x2;
}
SceneManager *createOctreeSceneManager()
{
return new Octree();
}
};
int main()
{
sel::State state;
state["Root"].SetClass<Root, int>("createOctreeSceneManager", &Root::createOctreeSceneManager);
//ERROR
state["SceneManager"].SetClass<SceneManager, int>("GetX", &SceneManager::GetX);
return 0;
}
OK I see. This fails currently because the SetClass function in Selene tries to automatically create a constructor. I can understand how this could be useful and I can probably add it as a separate method (SetAbstractClass).
Hi, I tried to make some changes but when I call 'print(sm:GetX())', i get nothing , and I don't know why.
//=========================Selector.h
template <typename T, typename... Funs>
void SetAbstractClass(Funs... funs) {
_traverse();
auto fun_tuple = std::make_tuple(funs...);
auto push = [this, &fun_tuple]() {
typename detail::_indices_builder<sizeof...(Funs)>::type d;
_registry.RegisterAbstractClass<T>(_name, fun_tuple, d);
};
_put(push);
lua_settop(_state, 0);
}
//=========================Registry.h
template <typename T, typename... Funs, size_t... N>
void RegisterAbstractClass(const std::string &name, std::tuple<Funs...> funs,
detail::_indices<N...>) {
RegisterAbstractClassWorker<T>(name, std::get<N>(funs)...);
}
template <typename T, typename... Funs>
void RegisterAbstractClassWorker(const std::string &name, Funs... funs) {
auto tmp = std::unique_ptr<BaseClass>(
new AbstractClass<T, Funs...>
{_state, _metatables, name, funs...});
_classes.push_back(std::move(tmp));
}
//=========================Added on Class.h
template <typename T,
typename... Members>
class AbstractClass : public BaseClass {
private:
bool _should_erase = true;
std::string _name;
std::string _metatable_name;
//std::unique_ptr<A> _ctor;
std::unique_ptr<Dtor<T>> _dtor;
using Funs = std::vector<std::unique_ptr<BaseFun>>;
Funs _funs;
MetatableRegistry& _meta_registry;
/*void _register_ctor(lua_State *state) {
_ctor.reset(new A(state, _metatable_name.c_str()));
}*/
void _register_dtor(lua_State *state) {
_dtor.reset(new Dtor<T>(state, _metatable_name.c_str()));
}
template <typename M>
void _register_member(lua_State *state,
const char *member_name,
M T::*member) {
_register_member(state, member_name, member,
typename std::is_const<M>::type{});
}
template <typename M>
void _register_member(lua_State *state,
const char *member_name,
M T::*member,
std::false_type) {
std::function<M(T*)> lambda_get = [member](T *t) {
return t->*member;
};
_funs.emplace_back(
new ClassFun<1, T, M>
{state, std::string{member_name}, _metatable_name.c_str(), lambda_get});
std::function<void(T*, M)> lambda_set = [member](T *t, M value) {
(t->*member) = value;
};
_funs.emplace_back(
new ClassFun<0, T, void, M>
{state, std::string("set_") + member_name,
_metatable_name.c_str(), lambda_set});
}
template <typename M>
void _register_member(lua_State *state,
const char *member_name,
M T::*member,
std::true_type) {
std::function<M(T*)> lambda_get = [member](T *t) {
return t->*member;
};
_funs.emplace_back(
new ClassFun<1, T, M>
{state, std::string{member_name},
_metatable_name.c_str(), lambda_get});
}
template <typename Ret, typename... Args>
void _register_member(lua_State *state,
const char *fun_name,
Ret(T::*fun)(Args...)) {
std::function<Ret(T*, Args...)> lambda = [fun](T *t, Args... args) {
return (t->*fun)(args...);
};
constexpr int arity = detail::_arity<Ret>::value;
_funs.emplace_back(
new ClassFun<arity, T, Ret, Args...>
{state, std::string(fun_name), _metatable_name.c_str(), lambda});
}
template <typename Ret, typename... Args>
void _register_member(lua_State *state,
const char *fun_name,
Ret(T::*fun)(Args...) const) {
std::function<Ret(const T*, Args...)> lambda =
[fun](const T *t, Args... args) {
return (t->*fun)(args...);
};
constexpr int arity = detail::_arity<Ret>::value;
_funs.emplace_back(
new ClassFun<arity, const T, Ret, Args...>
{state, std::string(fun_name), _metatable_name.c_str(), lambda});
}
void _register_members(lua_State *state) {}
template <typename M, typename... Ms>
void _register_members(lua_State *state,
const char *name,
M member,
Ms... members) {
_register_member(state, name, member);
_register_members(state, members...);
}
public:
AbstractClass(lua_State *state,
MetatableRegistry &meta_registry,
const std::string &name,
Members... members) : _name(name), _meta_registry(meta_registry) {
_metatable_name = _name + "_lib";
_meta_registry.Insert(typeid(T), _metatable_name);
luaL_newmetatable(state, _metatable_name.c_str());
_register_dtor(state);
//*removed* _register_ctor(state);
_register_members(state, members...);
lua_pushvalue(state, -1);
lua_setfield(state, -1, "__index");
}
~AbstractClass() {
if (_should_erase) _meta_registry.Erase(typeid(T));
}
AbstractClass(const AbstractClass &) = delete;
AbstractClass& operator=(const AbstractClass &) = delete;
AbstractClass(AbstractClass &&other)
: _should_erase{true}
, _name{std::move(other._name)}
, _metatable_name{std::move(other._metatable_name)}
// *removed* , _ctor{std::move(other._ctor)}
, _dtor{std::move(other._dtor)}
, _funs{std::move(other._funs)}
, _meta_registry{other._meta_registry} {
other._should_erase = false;
}
AbstractClass& operator=(AbstractClass &&other) {
if (&other == this) return *this;
_name = std::move(other._name);
_metatable_name = std::move(other._metatable_name);
//*removed* _ctor = std::move(other._ctor);
_dtor = std::move(other._dtor);
_funs = std::move(other._funs);
_meta_registry = other._meta_registry;
other._should_erase = false;
_should_erase = true;
return *this;
}
//=========================main.cpp
#include <iostream>
#include <selene.h>
class SceneManager
{
public:
virtual int GetX() = 0;
};
class Octree: public SceneManager {
public:
int x;
Octree() {
x = 0;
}
int GetX() {
return x;
}
};
class Root {
public:
int x;
Root(int num) { x = num; printf("created Root\n"); }
void SetX(int x2) {
x = x2;
}
SceneManager *createOctreeSceneManager()
{
printf("created OctreeSceneManager\n");
return new Octree();
}
};
int main()
{
sel::State state;
state["Root"].SetClass<Root, int>("createOctreeSceneManager", &Root::createOctreeSceneManager);
state["SceneManager"].SetAbstractClass<SceneManager>("GetX", &SceneManager::GetX);
state("root = Root.new(5); sm = root:createOctreeSceneManager(); print(sm:GetX())");
//prints:
//created Root
//created OctreeSceneManager
return 0;
}
I'm trying to add some abstract classes Ogre3D library, but without success.
It would be good to have support for this.
Ogre3D have some abstract classes, like Ogre::SceneManager, and we create a instance using Ogre::Root::createSceneManager and return a scene managers like Octree, BSP or Generic.