LuaState icon indicating copy to clipboard operation
LuaState copied to clipboard

Create instances of C++ classes in Lua 5.1.x

Open iSLC opened this issue 10 years ago • 3 comments

I've noticed that the library is able to register C++ classes but you are unable to instantiate them in Lua. I've seen this kind of ability in another project similar to this one called Selene.

Let's say I have the following (test) class:

struct Vec3
{
    // Member variables if possible.
    float x, y, z;
    // Code...

    // Multiple constructors if possible.
    Vec3() : x(0), y(0), z(0)
    {  }
    Vec3(float x, float y, float z) : x(x), y(y), z(z)
    {  }
    Vec3(const Vec3& vec) : x(vec.x), y(vec.y), z(vec.z)
    {  }
    // Code...

    // Operators if possible.
    Vec3 operator+(const Vec3& vec)
    { return Vec3(x + vec.x, y + vec.y, z + vec.z); }
    Vec3 operator-(const Vec3& vec)
    { return Vec3(x - vec.x, y - vec.y, z - vec.z); }
    // Code...

    // Member functions if possible.
    void zero()
    { x = y = z = 0; }
    void negate()
    { x = -x; y = -y; z = -z; }
    // Code...

    // Getters and setters if necessary.
    void set(float x, float y, float z)
    { this->x = x; this->y = y; this->z = z; }

    void setx(float x) { this->x = x; }
    void sety(float y) { this->y = y; }
    void setz(float z) { this->z = z; }

    float getx() { return x; }
    float gety() { return y; }
    float getz() { return z; }
    // Code...
};

And after I register in in Lua I should be able to do:

-- Multiple constructors if possible.
empty = Vec3.new()
specific = Vec3.new(5, 9, 2)
copy = Vec3.new(empty)

-- Operators if possible but NOT! a complete requirement.
copy = copy + specific

-- Member functions if possible.
specific.negate()
copy.empty()

-- Getters and setters if necessary.
copy.set(82, 33, 76)
ex empty.getx();
ey empty.gety();
ez empty.getz();

-- And so on....

But only if it's possible and in Lua 5.1.5 because I need to use it with LuaJit. The current library worked with my small tests however I need to be able to create new objects in Lua.

Selene is for Lua 5.2+ and therefore incompatible with LuaJit which is why is it doesn't fit my needs.

iSLC avatar Jun 21 '14 20:06 iSLC

I need some example to show how to bind to class, Can you show me?

zhaozg avatar Jun 23 '14 12:06 zhaozg

Unfortunately you can't bind whole classes, but is quite easy to buy existing instances like iSLC wrote... With std::bind:

class Foo
{
    int value;

public:

    void add(int number) { value += number; }
    void rem(int number) { value -= number; }
    void mul(int number) { value *= number; }
    void div(int number) { value /= number; }

    Foo(lua::State& state, const char* name) : value(0) {
        state.set(name ,lua::Table());
        lua::Value instance = state[name];

        instance.set("add", std::function<void(int)>(std::bind(&Foo::add, this, std::placeholders::_1)));
        instance.set("rem", std::function<void(int)>(std::bind(&Foo::add, this, std::placeholders::_1)));
        instance.set("mul", std::function<void(int)>(std::bind(&Foo::add, this, std::placeholders::_1)));
        instance.set("div", std::function<void(int)>(std::bind(&Foo::add, this, std::placeholders::_1)));
    }
};

Or with lambdas:

class Foo
{
public:
    int value;

    void add(int number) { value += number; }
    void rem(int number) { value -= number; }
    void mul(int number) { value *= number; }
    void div(int number) { value /= number; }

    Foo(lua::State& state, const char* name) : value(0) {
        state.set(name ,lua::Table());
        lua::Value instance = state[name];

        instance.set("add", [this](int number) { add(number); });
        instance.set("rem", [this](int number) { rem(number); });
        instance.set("mul", [this](int number) { mul(number); });
        instance.set("div", [this](int number) { div(number); });
    }
};

Simple use case:

#include <LuaState.h>
int main()
{
        lua::State state;
        Foo foo(state, "my_instance");
        state.doString("my_instance.add(10)");
        state.doString("my_instance.mul(2)");
        state.doString("my_instance.div(5)");
        assert(foo.value == 4);
}

AdUki avatar Jun 24 '14 08:06 AdUki

Got it, I need to write some wrap class for real class,wrap class works like lua module, This separate the lua world and c++ world, clearly. Some pattern maybe help us easy to know and use it.

Thnaks.

zhaozg avatar Jun 24 '14 12:06 zhaozg