5

ベースメンバーへのポインターを作成すると、通常は派生メンバーへのポインターに変換できますが、最初のテンプレート引数が2番目の引数に影響を与える以下のBuzzのようなテンプレート内で使用する場合は変換できません。私はコンパイラのバグと戦っていますか、それとも標準はこれが機能しないことを本当に義務付けていますか?

struct Foo
{
    int x;
};

struct Bar : public Foo
{
};

template<class T, int T::* z>
struct Buzz
{
};

static int Bar::* const workaround = &Foo::x;

int main()
{
    // This works. Downcasting of pointer to members in general is fine.
    int Bar::* y = &Foo::x;

    // But this doesn't, at least in G++ 4.2 or Sun C++ 5.9. Why not?
    // Error: could not convert template argument '&Foo::x' to 'int Bar::*'
    Buzz<Bar, &Foo::x> test;

    // Sun C++ 5.9 accepts this but G++ doesn't because '&' can't appear in
    // a constant expression
    Buzz<Bar, static_cast<int Bar::*>(&Foo::x)> test;

    // Sun C++ 5.9 accepts this as well, but G++ complains "workaround cannot
    // appear in a constant expression"
    Buzz<Bar, workaround> test;

    return 0;
}
4

1 に答える 1

5

それは単に許可されていません。§14.3.2/5によると:

以下の変換は、非型テンプレート引数として使用される各式で実行されます。非型のtemplate-argumentを対応するtemplate-parameterの型に変換できない場合、プログラムの形式は正しくありません。
—整数型または列挙型の非型テンプレートパラメータの場合、整数拡張(4.5)および積分変換(4.7)が適用されます。
—オブジェクトへの型ポインターの非型テンプレートパラメーターの場合、資格変換(4.4)および配列からポインターへの変換(4.2)が適用されます。—オブジェクトへの型参照の非型テンプレートパラメータの場合、変換は適用されません。参照によって参照されるタイプは、テンプレート引数の(それ以外の場合は同一の)タイプよりもcv修飾されている可能性があります。template-parameterはtemplate-argumentに直接バインドされており、これは左辺値である必要があります。
—関数への型ポインターの非型テンプレートパラメーターの場合、関数からポインターへの変換(4.3)のみが適用されます。template-argumentがオーバーロードされた関数のセット(またはそのような関数へのポインター)を表す場合、一致する関数がセット(13.4)から選択されます。
—関数への型参照の非型テンプレートパラメータの場合、変換は適用されません。template-argumentがオーバーロードされた関数のセットを表す場合、一致する関数がセット(13.4)から選択されます。
—メンバー関数への型ポインターの非型テンプレートパラメーターの場合、変換は適用されません。template-argumentがオーバーロードされたメンバー関数のセットを表す場合、一致するメンバー関数がセット(13.4)から選択されます。
データメンバーへの型ポインターの非型テンプレートパラメーターの場合、資格変換(4.4)が適用されます。

データメンバーへのポインタに関する変換を強調しました。変換(§4.11/ 2)はリストされていないことに注意してください。C ++ 0xでは、この点で同じままです。

于 2010-10-26T19:35:49.973 に答える