3

I'm trying to implement a Vector3 class in Lua using Luabridge. So far I am able to construct it, and access each component like you'd expect (x, y, z). An example in Lua would look like this:

local v = Vec3(0, 0, 0)

Now, I'd like to overload the arithmetic operators, starting with addition. I'm using glm as my backbone math library, so I only have access to the global operator + they defined. Because of this, the only way I've been able to get this to work is by using luabridge's addStaticFunction, currently my class registration looks something like this:

luabridge::getGlobalNamespace(L)
.beginClass<vec3>("Vec3")
.addConstructor<void(*)(f32, f32, f32)>()
.addProperty("x", &VecProperty<vec3, f32>::Get<0>, &VecProperty<vec3, f32>::Set<0>)
.addProperty("y", &VecProperty<vec3, f32>::Get<1>, &VecProperty<vec3, f32>::Set<1>)
.addProperty("z", &VecProperty<vec3, f32>::Get<2>, &VecProperty<vec3, f32>::Set<2>)
.addStaticFunction("__add", (vec3(*)(const vec3&, const vec3&)) & ::operator+)
.endClass();

However, when I try to use it, for example:

Vec3(0, 0, 0) + Vec3(1, 1, 1)

I get the following exception: attempt to perform arithmetic on a userdata value

Oddly enough, if I just use the function directly it works, for example:

Vec3.__add(Vec3(0, 0, 0), Vec3(1, 1, 1))

From my understanding, the fact that in Vec3's metatable there exist a function called __add it should be able to use this for the arithmetic operator also. This is clearly not the case, but I can't find any resources explaining what else needs to be done to get this to work.

I've seen a similar question posted here: Luabridge binding overloaded operators

In his example, however, he has access to the non-global operator, which is where my question differs.

Belfer4
  • 351
  • 3
  • 11
  • There is only one place a function pointer cast should ever appear, and that is on the return value of `GetProcAddress` (Windows) or `dlsym` (POSIX). Function pointer casts anywhere else are unnecessary at best and otherwise hiding errors. – Ben Voigt Aug 03 '21 at 17:23
  • How else I am to get the right function then? – Belfer4 Aug 03 '21 at 17:41
  • 1
    Initialization of a local variable or a temporary will both trigger the same conversion but without the danger of a cast. For example with the helper `template T implicit_convert(T t) { return t;}`, then you can use `implicit_convert(&::operator+)` – Ben Voigt Aug 03 '21 at 17:48
  • That will let the compiler check the types and not just blindly force the function address into a new function pointer. – Ben Voigt Aug 03 '21 at 17:48
  • Interesting, I will keep that in mind from now on, thanks for the heads up! – Belfer4 Aug 03 '21 at 17:52
  • @BenVoigt: `static_cast` is also safe in that regard and needs no helper (statement). – Davis Herring Aug 03 '21 at 23:06
  • @DavisHerring: `static_cast` is much stronger than my `implicit_convert` helper and is not safe in general. – Ben Voigt Aug 04 '21 at 14:48

0 Answers0