我在当前项目中托管SpiderMonkey,并希望模板函数生成一些简单的属性get / set方法,例如:
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;
}
用于:
::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}
};
但是,如果我添加另一个成员类型,则可以正常工作:
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;
}
然后Visual C ++ 9尝试使用J32bject *包装器作为int32成员!
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
令人惊讶的是,填充JSObject *会导致解析错误! (意外'(')。这可能是VC ++错误(任何人都可以测试“模板void foo(){}”在GCC编译吗?)。与“typedef JSObject * PObject; ...,PObject TClassImpl ::相同的错误” mem&gt;“,void ,struct Undefined *和double。由于函数用法完全实例化:”&amp; ReadProp“,应该没有正常的函数重载语义发挥作用,它是一个定义的此时的函数优先于模板函数。模板排序似乎在这里失败。
Vec2只是:
class Vec2
{
public:
int32 x, y;
Vec2(JSContext* cx, JSObject* obj, uintN argc, jsval* argv);
static ::JSClass s_JsClass;
static ::JSPropertySpec s_JsProps[];
};
JSP中的JSAPI链接描述了JSPropertySpec,取自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;
};
答案 0 :(得分:3)
非常确定VC ++在这里有“问题”。 Comeau和g ++ 4.2都对以下程序感到满意:
struct X
{
int i;
void* p;
};
template<int X::*P>
void foo(X* t)
{
t->*P = 0;
}
template<void* X::*P>
void foo(X* t)
{
t->*P = 0;
}
int main()
{
X x;
foo<&X::i>(&x);
foo<&X::p>(&x);
}
然而,VC ++ 2008SP1却没有。
我没有时间阅读我的标准,以确切了解到什么......但我认为VC ++在这里是错误的。
答案 1 :(得分:0)
尝试将JSObject *更改为另一种指针类型,以查看是否重现了该错误。 JSObject是否在使用点定义?此外,也许JSObject *需要在parens中。
答案 2 :(得分:0)
我当然不是模板专家,但这是否归结为一个微妙的情况,试图根据返回类型区分重载?
由于C ++不允许基于返回类型重载函数,因此模板参数也许同样适用。