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)
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.
#include
#include
#include
#include
#include
using namespace std;
#include
#include
#include
using namespace std;
template::value, int> = 0>
T convert_type(U _in)
{
//return const_cast(_in);
return _in;
}
template>::value, int> = 0>
T convert_type(U _in)
{
//return const_cast(_in);
return _in;
}
// these conversion functions only can convert type to pointer to type, else return reference to type, so they're a bit limited
// pointer to pointer, or
template>::value, int> = 0>
T& convert_type(U& _in)
{
return _in;
}
template>::value, int> = 0>
T& convert_type(U& _in)
{
return _in;
}
template>>::value, int> = 0>
T& convert_type(U& _in)
{
return _in;
}
// for conversion to pointer
//T&* to T*
template>::value, int> = 0>
T convert_type(U& _in)
{
return std::addressof(_in);
}
template>::value, int> = 0>
T convert_type(U& _in)
{
return std::addressof(_in);
}
template>>::value, int> = 0>
T convert_type(U& _in)
{
return std::addressof(_in);
}
template
struct function_traits;
template
struct function_traits>
{
static const size_t nargs = sizeof...(Args);
typedef R result_type;
template
struct arg
{
typedef typename std::tuple_element>::type type;
};
static const bool isGlobalOrStaticContainer = true;
static const bool isClassContainer = false;
static const bool isPointerContainer = false;
static const bool isConstInClassContainer = false;
static const bool returnsVoid = std::is_same::value;
};
template
struct function_traits>
{
static const size_t nargs = sizeof...(Args);
typedef R result_type;
template
struct arg
{
typedef typename std::tuple_element>::type type;
};
static const bool isGlobalOrStaticContainer = false;
static const bool isClassContainer = false;
static const bool isPointerContainer = true;
static const bool isConstInClassContainer = false;
static const bool returnsVoid = std::is_same::value;
};
template
struct function_traits>
{
static const size_t nargs = sizeof...(Args);
typedef R result_type;
template
struct arg
{
typedef typename std::tuple_element>::type type;
};
static const bool isGlobalOrStaticContainer = false;
static const bool isClassContainer = true;
static const bool isPointerContainer = false;
static const bool isConstInClassContainer = false;
static const bool returnsVoid = std::is_same::value;
};
template
struct function_traits>
{
static const size_t nargs = sizeof...(Args);
typedef R result_type;
template
struct arg
{
typedef typename std::tuple_element>::type type;
};
static const bool isGlobalOrStaticContainer = false;
static const bool isClassContainer = true;
static const bool isPointerContainer = false;
static const bool isConstInClassContainer = true;
static const bool returnsVoid = std::is_same::value;
};
template class Param
{
public:
typedef ParamType Type;
static const bool isOut = false;
};
template class ParamOut : public Param
{
public:
static const bool isOut = true;
};
template
static bool UnwrapParameter(unsigned argc, std::vector& args, typename ParamType::Type &ppt)
{
if (argc > paramIndex)
{
ppt = *((std::add_pointer_t(args[paramIndex])));
}
return true;
}
template
static bool UnwrapParameters(unsigned argc, std::vector& args, std::tuple& params, std::index_sequence)
{
bool r[] = { true, UnwrapParameter(argc, args, std::get(params))... };
bool res = true;
for (size_t i = 0; i < sizeof...(ParamType) + 1 && res == true; i++)
res &= r[i];
return res;
}
template
static bool UnwrapParameters(unsigned argc, std::vector& args, std::tuple& params)
{
return UnwrapParameters(argc, args, params, std::make_index_sequence{});
}
template
static bool WrapParameter(unsigned argc, std::vector& args, typename ParamType::Type &ppt)
{
if (ParamType::isOut && (argc > paramIndex))
{
// Wrap them back - nothing to do here, in this example
}
return true;
}
template
static bool WrapParameters(unsigned argc, std::vector& args, std::tuple& params, std::index_sequence)
{
bool r[] = { true, WrapParameter(argc, args, std::get(params))... };
bool res = true;
for (size_t i = 0; i < sizeof...(ParamType)+1 && res == true; i++)
res &= r[i];
return res;
}
template
static bool WrapParameters(unsigned argc, std::vector& args, std::tuple& params)
{
return WrapParameters(argc, args, params, std::make_index_sequence{});
}
template::type>>::isPointerContainer, MethodType>::type Method,
typename... ParamType, size_t... paramIndex>
static ReturnType CallMethodRet(bool& success, Type* obj, std::tuple& params, std::index_sequence)
{
if (!(obj && (obj->*Method)))
success = false;
return (obj->*Method)(convert_type::type>>::template arg::type, typename ParamType::Type>(std::get(params))...);
}
template::type>>::isGlobalOrStaticContainer, MethodType>::type Method,
typename... ParamType, size_t... paramIndex>
static ReturnType CallMethodRet(bool& success, Type* obj, std::tuple& params, std::index_sequence)
{
if (!(*Method))
success = false;
return (*Method)(convert_type::type>>::template arg::type, typename ParamType::Type>(std::get(params))...);
}
template::type>>::isClassContainer, MethodType>::type Method,
typename... ParamType, size_t... paramIndex>
static ReturnType CallMethodRet(bool& success, Type* obj, std::tuple& params, std::index_sequence)
{
if (!(obj && (Method)))
success = false;
return (obj->*Method)(convert_type::type>>::template arg::type, typename ParamType::Type>(std::get(params))...);
}
template
static ReturnType CallMethodRet(bool& success, Type* obj, std::tuple& params)
{
return CallMethodRet(success, obj, params, std::make_index_sequence{});
}
template::type>>::returnsVoid, MethodType>::type Method,
typename... ParamType>
static bool ExecuteMethod(Type* obj, unsigned argc, std::vector& args, ReturnType& result)
{
try
{
const unsigned numArgs = sizeof...(ParamType);
std::tuple params = std::make_tuple(typename ParamType::Type()...);
if (!UnwrapParameters(argc, args, params))
return false;
bool success = true;
result = CallMethodRet(success, obj, params);
if (!success)
return false; // Throw method not found here
if (!WrapParameters(argc, args, params))
return false;
}
catch (...)
{
// whatever...
}
return true;
}
template::type>>::returnsVoid, MethodType>::type Method,
typename... ParamType>
static bool ExecuteMethod(Type* obj, unsigned argc, std::vector& args)
{
try
{
const unsigned numArgs = sizeof...(ParamType);
std::tuple params = std::make_tuple(typename ParamType::Type()...);
if (!UnwrapParameters(argc, args, params))
return false;
bool success = true;
CallMethodRet(success, obj, params);
if (!success)
return false; // Throw method not found here
if (!WrapParameters(argc, args, params))
return false;
}
catch (...)
{
// whatever...
}
return true;
}
class O
{
public:
void func(int a, string b, bool& c, const char* d)
{
std::cout << "Successfully called func with in values " << a << "," << b << "," << c << " and " << d << std::endl;
c = true;
std::cout << "Successfully called func with out values " << a << "," << b << "," << c << " and " << d << std::endl;
}
int func_i(int a, string b, bool& c, const char* d)
{
std::cout << "Successfully called func with in values " << a << "," << b << "," << c << " and " << d << std::endl;
c = false;
std::cout << "Successfully called func with out values " << a << "," << b << "," << c << " and " << d << std::endl;
return 1;
}
};
int main() {
int a = 1;
string b = "string";
bool c = false;
const char* d = "char*";
std::vector v {(void*)&a, (void*)&b, (void*)&c, (void*)&d};
std::cout << std::endl;
O o;
std::cout << ExecuteMethod, Param, ParamOut, Param>(&o, v.size(), v);
std::cout << std::endl << std::endl;
int result = 0;
std::cout << ExecuteMethod, Param, ParamOut, Param>(&o, v.size(), v, result) << std::endl;
std::cout << result << std::endl;
return 0;
}