Rapptz / sol

A C++11 Lua wrapper
MIT License
209 stars 32 forks source link

Overloaded Userdata Functions #43

Closed notlion closed 10 years ago

notlion commented 10 years ago

Is there a way to select which version of a overloaded function to use when creating userdata? This is a class similar to the one I'm trying to bind:

struct vector {
  float x = 0;
  float y = 0;
  vector() = default;
  void set(float x_, float y_) { x = x_; y = y_; }
  void set(const vector& v) { x = v.x; y = v.y; }
};

So given that there are two versions of set, how do I choose which one to bind?

sol::userdata<vector>("vector", ctor, "set", &vector::set); // Doesn't work
ThePhD commented 10 years ago

Unfortunately, the way you have to do it is by static_cast-ing the function signature you want on this to work properly:

static_cast<void (vector::*) ( float, float )>( &vector::set );

Replace (float, float) with the arguments to you, and void with the return type, etc. etc.

ThePhD commented 10 years ago

Note that in the bowels of sol, we do some overload in-fighting to figure out the proper thing with the set_function syntax. It might be worth elevating this to a regular free-function that users can use to avoid this problem entirely.

notlion commented 10 years ago

Thanks! The static cast works well enough. It would be nice to have something akin to set_function<void(float, float)>() for userdata. Related question: Is it possible to modify userdata after it is created?

ThePhD commented 10 years ago

I don't think allowing modification of userdata<T> after it's been made to be a wise design decision, plus it actually will make a few things much harder about automatic cleanup (we can get away with using non-garbage free functions for cleanup of userdata metatables because we are using variadic templates to guarantee a fixed, compile-time count of the number of functions associated with a userdata type).

ThePhD commented 10 years ago

That being said, an "easy" overload resolution "resolve" function would be helpful, and would also help us identify an error with some clang overload resolution problems.

notlion commented 10 years ago

Resolve would be nice. Basically something like this?

sol::userdata<Vec2f> udata("Vec2", ctor, "set", sol::resolve<float, float>(&Vec2f::set));

This was my use case but for some reason I was thinking about it in terms of modifying userdata after creation. This seems simpler.

ThePhD commented 10 years ago

So I have a version of that working... in g++. Clang barfs because of the return type, so I need to add an extra level of indirection to make clang behave.

ThePhD commented 10 years ago

Just checked in something for this (resolve.hpp). Note how if you're using clang (or plan to build with clang), clang does not nicely handle specifying the arguments only, so you MUST specify the full signature if you want to build with clang.

With g++, you can use the argument-only form and everything should be peachy-keen. g++:

sol::userdata<Vec2f> udata("Vec2", ctor, "set", sol::resolve<float, float>(&Vec2f::set));

clang:

sol::userdata<Vec2f> udata("Vec2", ctor, "set", sol::resolve<void(float, float)>(&Vec2f::set));

The clang version will work everywhere.

notlion commented 10 years ago

Awesome. Yup, I'm stuck with clang because I'm targeting iOS / using Xcode. Interestingly, when the return type is void, these work (where T is double):

sol::resolve<T, T>(&VecT::set) // void(T, T)
sol::resolve<const Vec2<T>&>(&MatrixT::scale) // void(const Vec2<T>&)

But this does not:

sol::resolve<T>(&MatrixT::rotate) // void(T)

Thanks for the improvement. Sol is really nice so far!

ThePhD commented 10 years ago

Yeah, clang is weird... I think it actually might be a defect in clang, the more I think about it. I will have to ask.

But glad it's all good. If you run into any more peculiarities or things, feel free to drop more bug reports. If you have any interesting library ideas, feel free to drop feature requests too!

ThePhD commented 10 years ago

As it stands, it seems Clang's actually completely correct in not being able to resolve things. It's more "conformant" behavior (according to 14.8.1 [temp.arg.explicit]/9 pointed out by Stephan T. Lavavej), so... yeah. I guess g++ isn't conforming. Use the signature version ( R( Args... ) ) to be as explicit as possible, or static_cast.

Rapptz commented 10 years ago

This has been fixed.