I have studied a lot templates with variadic pack expansion, but still I can't compile all the articles I've found here in order to achieve my goal. Please accept my apologies for being, probably, redundant. I am bound to some APIs and I am tied to some function signatures like here:
static bool WrapperFunction(JSContext *cx, unsigned argc, JS::Value *vp)
I try to wrap objects and functions to use in javascript under SpiderMonkey. To integrate some C API, must be implemented wrappers for object data and wrapper methods for some object.
My solution lead me to the following logic of the wrapper, in order to be able to call methods with several arguments, but I don't know how to achieve it:
template<typename jsType, typename jsReturnType, typename MethodType, MethodType Method, typename... jsParamType>
static bool VAMethodRet(JSContext *cx, unsigned argc, JS::Value *vp)
{
JS::CallArgs args = CallArgsFromVp(argc, vp);
jsReturnType::PrivateType result = jsReturnType::PrivateTypeDefaultValue();
Here begin my issues.
First step. Expand ...jsParamType... pack with calling a method for each jsParamType in order to create a wrapper class object instance for matching the corresponding argument out of args to prepare calling the C API function.
In other words, jsParamType tells the type it wraps so it can extract the C type object for each parameter to be passed to the C API function.
The first jsParamType corresponds to the args[0], the second jsParamType to the args1 etc., to the last jsParamType, which corresponds the args[argc].
It is possible to get less elements in args than sizeof...jsParamType, in this case the base C object should be initialized with a default value.
The meta-information of parameters or object wrappers is achieved with static methods already (jsParamType::jsType::PrivateTypeDefaultValue() for example).
Eventually, the expanded pack should be an array or vector of heterogeneous objects.
The matching function should be templated, based on jsParamType, but also get the index of the expanded variadic pack and the args local variable in order to get the correct object to parse - here is my first issue:
How to pass the index to the method?
I've tried to have some inspiration out of here, but I can't make it work: Calling a function for each variadic template argument and an array
Second step. After this, I plan to have a similar technique to here: Obtain Argument Index while Unpacking Argument List with Variadic Templates in order to call the C API function with the right arguments - is this possible?
Third step. In the end, based on a static function of jsParamType, called IsOut(), the out values will update the content of args local variable, but this should be done again using a new expansion, similar to the first step, to put back some values using type info present in jsParamType elements.
The last thing to do would be to set the return value, which is trivial.
Legend: jsType is a type of the struct containing the pointer to the C API functions, as these are grouped by the C API's provider. jsReturnType is the return type. (just for reference here...) Method is a C API method to be called, having the MethodType type.
Please help me to write such code, as I can't get it work. I don't ask to think for me and be my private coders. I just have no experience with this part of the preprocessor, I see lots of examples, many throw errors, or I can't extend them in order to achieve the above function. Thank you.
EDIT 1
Thanks for the reply, AndyG. Here is the more or less pseudo-code:
// *jsType* is a type of the struct containing the pointer to the C API functions, as these are grouped by the C API's provider.
// *jsReturnType* is the return type. (just for reference here...)
// *Method* is a C API method to be called, having the *MethodType* type.
// The non-template part of the function signature is needed untouched by SpiderMonkey
template<typename jsType, typename jsReturnType, typename MethodType, MethodType Method, typename... jsParamType>
static bool VAMethodRet(JSContext *cx, unsigned argc, JS::Value *vp)
{
// get the collection of passed arguments (SpiderMonkey stuff), in args, each element accessible by index
// argc is the number of parameters passed from javascript
WrappersCollection args = GetCallArgsFromVp(argc, vp);
jsReturnType::PrivateType result = jsReturnType::PrivateTypeDefaultValue(); // creates an instance of a return value wrapper to receive the return value later
// 1. Match wrappers in the WrappersCollection against their types in order to get their C type values
CDataCollection cdata = array or vector of heterogeneous objects (int, char*, structs etc.);
for each (jsParamType in the variadic pack ...)
{
cdata[jsParamTypeIndex] = Match<jsParamType, jsParamTypeIndex>(args);
}
// the above should be done by expanding the pack somehow
// with emphasis on checking if argc[jsParamTypeIndex] was passed actually, because it's possible to have jsParamTypeIndex > argc
// I don't know how to do it otherwise, by matching some param types variadic pack against a variadic pack of data arguments with different number of elements
// 2. Transform the cdata collection into a variadic parameters pack in order to pass them to the C function.
// The amount of args is specified by the function
result = CFunction(cdata...);
// 3. Update returned data in *out* params in the collection of wrapper objects received in the first place
// index of the param in pack is necessary again
// due to the different number of elements in the param types variadic pack versus the variadic pack of data arguments
for each (jsParamType in the variadic pack ...)
{
if (jsParamType::IsOUT())
{
cdata[jsParamTypeIndex] = MatchBack<jsParamType, jsParamTypeIndex>(args);
}
}
// the rest of things to do
MatchReturnValue(result);
return true; // SpiderMonkey needs to know the success of the operation
}
Is this more comprehensible enough?
Thanks to the help and patience of AndyG, I have achieved my goal. Here is a sample of code with the note that actual wrappers are not provided, as they are specific from case to case. So, they are simulated by simply passing parameters.