I am hosting SpiderMonkey in a current project and would like to have template functions generate some of the simple property get/set methods, eg:
template <typename TClassImpl, int32 TClassImpl::*mem> JSBool JS_DLL_CALLBACK WriteProp(JSContext* cx, JSObject* obj, jsval id, jsval* vp) { if (TClassImpl* pImpl = (TClassImpl*)::JS_GetInstancePrivate(cx, obj, &TClassImpl::s_JsClass, NULL)) return ::JS_ValueToInt32(cx, *vp, &(pImpl->*mem)); return JS_FALSE; }
Used:
::JSPropertySpec Vec2::s_JsProps[] = { {'x', 1, JSPROP_PERMANENT, &JsWrap::ReadProp<Vec2, &Vec2::x>, &JsWrap::WriteProp<Vec2, &Vec2::x>}, {'y', 2, JSPROP_PERMANENT, &JsWrap::ReadProp<Vec2, &Vec2::y>, &JsWrap::WriteProp<Vec2, &Vec2::y>}, {0} };
This works fine, however, if I add another member type:
template <typename TClassImpl, JSObject* TClassImpl::*mem> JSBool JS_DLL_CALLBACK WriteProp(JSContext* cx, JSObject* obj, jsval id, jsval* vp) { if (TClassImpl* pImpl = (TClassImpl*)::JS_GetInstancePrivate(cx, obj, &TClassImpl::s_JsClass, NULL)) return ::JS_ValueToObject(cx, *vp, &(pImpl->*mem)); return JS_FALSE; }
Then Visual C++ 9 attempts to use the JSObject* wrapper for int32 members!
1>d:\projects\testing\jswnd\src\main.cpp(93) : error C2440: 'specialization' : cannot convert from 'int32 JsGlobal::Vec2::* ' to 'JSObject *JsGlobal::Vec2::* const ' 1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast 1>d:\projects\testing\jswnd\src\main.cpp(93) : error C2973: 'JsWrap::ReadProp' : invalid template argument 'int32 JsGlobal::Vec2::* ' 1> d:\projects\testing\jswnd\src\wrap_js.h(64) : see declaration of 'JsWrap::ReadProp' 1>d:\projects\testing\jswnd\src\main.cpp(93) : error C2440: 'initializing' : cannot convert from 'overloaded-function' to 'JSPropertyOp' 1> None of the functions with this name in scope match the target type
Surprisingly, parening JSObject* incurs a parse error! (unexpected ‘(‘). This is probably a VC++ error (can anyone test that ‘template void foo() {}’ compiles in GCC?). Same error with ‘typedef JSObject* PObject; …, PObject TClassImpl::mem>’, void, struct Undefined*, and double. Since the function usage is fully instantiated: ‘&ReadProp’, there should be no normal function overload semantics coming into play, it is a defined function at that point and gets priority over template functions. It seems the template ordering is failing here.
Vec2 is just:
class Vec2 { public: int32 x, y; Vec2(JSContext* cx, JSObject* obj, uintN argc, jsval* argv); static ::JSClass s_JsClass; static ::JSPropertySpec s_JsProps[]; };
JSPropertySpec is described in JSAPI link in OP, taken from header:
typedef JSBool (* JS_DLL_CALLBACK JSPropertyOp)(JSContext *cx, JSObject *obj, jsval id, jsval *vp); ... struct JSPropertySpec { const char *name; int8 tinyid; uint8 flags; JSPropertyOp getter; JSPropertyOp setter; };
Pretty sure VC++ has ‘issues’ here. Comeau and g++ 4.2 are both happy with the following program:
VC++ 2008SP1, however, is having none of it.
I haven’t the time to read through my standard to find out exactly what’s what… but I think VC++ is in the wrong here.