5

私は現在のプロジェクトで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 は、int32 メンバーに対して JSObject* ラッパーを使用しようとします。

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++ エラーです ("template void foo() {}" が GCC でコンパイルされることをテストできる人はいますか?) "typedef JSObject* PObject; ..., PObject TClassImpl:: mem>"、void、struct Undefined*、および double。関数の使用法は完全にインスタンス化されているため ("&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[];
};

JSPropertySpec は、ヘッダーから取得した OP の JSAPI リンクで説明されています。

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;
};
4

3 に答える 3

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++はここでは間違っていると思います。

于 2008-09-22T01:08:42.260 に答える
0

JSObject * を別のポインター型に変更して、エラーが再現されるかどうかを確認してください。JSObject は使用時に定義されていますか? また、おそらく JSObject* は括弧で囲む必要があります。

于 2008-09-22T00:41:29.690 に答える
0

私は確かにテンプレートの第一人者ではありませんが、これは純粋に戻り値の型に基づいてオーバーロードを区別しようとする微妙なケースに要約されますか?

C++ では戻り値の型に基づく関数のオーバーロードが許可されていないため、おそらく同じことがテンプレート パラメーターにも当てはまります。

于 2008-09-22T00:51:24.627 に答える