vinniefalco / LuaBridge

A lightweight, dependency-free library for binding Lua to C++
1.62k stars 347 forks source link

Vector3 operator + overloading #257

Open Belfer opened 3 years ago

Belfer commented 3 years ago

I'm trying to get the operators for my math vec3 class into lua, consider the following line:

luabridge::getGlobalNamespace(L).addFunction("__add", (vec3(*)(const vec3&, const vec3&)) & ::operator+);

This ofc doesn't work for me, as I believe the metatable for vec3 isn't bound to the __add function above. My problem is that it's not an option to have the operator in the class so I have to use the global operator.

Is there a way to do this?

The closest thing I could find is this issue: https://github.com/vinniefalco/LuaBridge/issues/117 But the post from m1k0s doesn't show the scope from which he calls addFunction.

Belfer commented 3 years ago

Ok now I'm pretty confused, I tried using the addStaticFunction when defining the class like such:

luabridge::getGlobalNamespace(L)
.beginClass<vec3>("Vec3")
.addStaticFunction("__add", (vec3(*)(const vec3&, const vec3&)) & ::operator+)
.endClass();

Which in the Lua script works if I write: Vec3.__add(Vec3(), Vec3()) But not this: Vec3() + Vec3()

Seems really odd to me, but at least I'm getting closer I think.

Belfer commented 2 years ago

The exception catch is the following: attempt to perform arithmetic on a userdata value Any help would be greatly appreciated here!

kunitoki commented 2 years ago

Have you tried:


luabridge::getGlobalNamespace(L)
  .beginClass<vec3>("Vec3")
    .addFunction("__add", (vec3(*)(const vec3&, const vec3&)) & ::operator+)
  .endClass();
dmitry-t commented 2 years ago

@Belfer Lua follows the specific rules, citation is below.

Briefly, you can only overload an arithmetic operator bound to a class instance.

The @kunitoki sample does exactly that: it registers the free C++ function as an instance function. After that Lua finds the function in the Vector3 metatable.

"add": the + operation.

The function getbinhandler below defines how Lua chooses a handler for a binary operation. First, Lua tries the first operand. If its type does not define a handler for the operation, then Lua tries the second operand.

 function getbinhandler (op1, op2, event)
   return metatable(op1)[event] or metatable(op2)[event]
 end

By using this function, the behavior of the op1 + op2 is

 function add_event (op1, op2)
   local o1, o2 = tonumber(op1), tonumber(op2)
   if o1 and o2 then  -- both operands are numeric?
     return o1 + o2   -- '+' here is the primitive 'add'
   else  -- at least one of the operands is not numeric
     local h = getbinhandler(op1, op2, "__add")
     if h then
       -- call the handler with both operands
       return (h(op1, op2))
     else  -- no handler available: default behavior
       error(···)
     end
   end
 end