(関数) テンプレートへの C++ 非型パラメーターは順序付けされていますか?
-
02-07-2019 - |
質問
私が主催しています クモザル 現在のプロジェクトで、テンプレート関数にいくつかの単純なプロパティの 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>"、無効, 、struct Unknown*、および 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;
};
解決
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++が間違っていると思います。
他のヒント
JSObject * を別のポインター型に変更して、エラーが再現されるかどうかを確認してください。JSObject は使用時に定義されていますか?また、JSObject* は括弧で囲む必要があるかもしれません。
私は確かにテンプレートの専門家ではありませんが、これは純粋に戻り値の型に基づいてオーバーロードを区別しようとする微妙なケースに要約されるのでしょうか?
C++ では戻り値の型に基づいた関数のオーバーロードが許可されていないため、おそらく同じことがテンプレート パラメーターにも当てはまります。