Registering method with packed argument


It would be fantastic to be able to register a method with a packed argument.
To get a little more into my scenario.

Lets say i have a std::set member on a class.
I figured out how to setup a method to unpack them and add to the container.

// C++
auto inst = Foo();
inst.setProps(ENUM_X, ENUM_Y, ENUM_Z); // this works with regular c++

what i need is to figure out how to tell chaiscript about the packed argument

engine.add(chaiscript::fun<void(Enum...)>(&Foo::setProps), "setProps");

// Chaiscript
inst.setProps(ENUM_X, ENUM_Y, ENUM_Z);


Can you clarify what the signature of setProps is in your C++ code?


I went with the following

// C++
template <typename ...Args>
auto setProps(Args&&... args) -> bool {
	return expand_impl(m_container, std::forward<Args>(args)...);
template <typename T>
void expand_impl(T) { }
template <typename T, typename ...Tail>
void expand_impl(T& container, const Color& head, Tail&&... tail) {
	expand_impl(container, std::forward<Tail>(tail)...);

I hope that helps.
Maybe to clarify what i am trying to do with this.
My first approach was to make an alias for std::vector and expose that to chaiscript in the script code i would then construct a temporary vector templated onto the enum and push_back the values and then pass that to setProps for example.
The C++ code would then loop over that vector and copy over the values, A unpacking solution would be very much cleaner and i believe other people will benefit from that approach if it was decently documented.
One alternative i could think of is to get uniform initialization syntax going inside chaiscript and have it be the same as we have with C++11.

From what i understand using

var vec = [3, 5, 7];

only refers to a vector collection capable of holding known primitives and not a collection of values in a more general sense.


Something like uniform initialization syntax might be workable, but trying to generically unpack a variadic template function is impossible in C++, since the function doesn’t actually exist until you instantiate it.

It might be possible to give it a set of expansions to work from, or some guidance, like maybe something like:

chai.add(template_fun<somevariadicfunction, void (int), void (int, int), void (int, double, float)>("somevariadicfunction"));

Which would take the function template and register it with the 3 different signatures provided

or maybe

chai.add(expanded_template_fun<somevaridacfunction, int, 2, 5>("somevariadicfunction"));

Which would take the variadic function template and register it 4 times (from 2 to 5 parameters), expanded out like:

void (int, int)
void (int, int, int)
void (int, int, int, int)
void (int, int, int, int, int)

This statement basically describes exactly how ChaiScript works internally. A vector of Boxed_Value that is tested against the expected C++ types in the known C++ function calls that are registered.

That understand is incorrect. You can store any type of value in a vector, and they don’t have to be homogeneous.

var vec = [1, 3.4, "bob", fun(x){ x+2 }, async(fun(){ 34+5 })]
// int, double, string, function object, std::future<Boxed_Value>

That code should be perfectly legitimate (assuming no parser errors ;))

I think you might risk accidentally re-implementing ChaiScript if you try too hard here, and should instead see what parts you can implement in ChaiScript itself.

I cannot help but think that your setProps code seems a bit over-engineered since you know ahead of time (based on m_container) what the types needed will be. In fact, in expand_impl you limit yourself specifically to Color objects.

But I’m probably missing the bigger picture here.

But if I do understand correctly, you could probably do something like this:

// cpp
void setProps(const std::vector<Color> &vec) {
  for(const auto &c : vec) {

// somewhere else
chai.add(chaiscript::vector_conversion<std::vector<Color>>()); // maybe this vector conversion is what you were missing??
chai.add(chaiscript::fun(&setProps), "setProps");
// chaiscript
setProps([Color(255,255,255), Color(255,0,0)]);



This is exactly what i am already doing.
I’m not trying to re-implement Chaiscript but rather figure out how to best use it as flexible as possible. :wink:
Though since you already saw the Color Enum together with my bulk enum registration pull request.

when i try to call


an exception is thrown

Error: "Can not find appropriate 'clone' or copy constructor for vector elements" during evaluation...

I expect that is because the enum doesn’t have the required methods.
I would really like to stick with my enum approach since it makes using human readable values accessible inside the script.


Aaah. That should be fixable, but it will take a little bit of research. You literally need to add a copy constructor for your enum type, as if it were any other class. This is something we should be able to make happen almost completely automatically.


Ok, I’m definitely confused… what type is red in your example? Is it an enum? If so - I’m unable to reproduce the issue your are describing.



Here is a small testcase.

int main(int argc, char **argv) {
	enum Color {
	try {
		chaiscript::ChaiScript engine(chaiscript::Std_Lib::library());
		engine.add(chaiscript::const_var(blue), "blue");
		engine.add(chaiscript::const_var(red), "red");
		engine.add(chaiscript::user_type<Color>(), "Color");
		engine.eval("return [red]");
	catch (const chaiscript::exception::eval_error &e) {
		std::cout << "Error\n" << e.pretty_print() << '\n';
	return 0;