2

言語弁護士のための別のもの。

次のコードでは、 の明示的なインスタンス化A<int>が存在するかどうかに関係なく:

clang 3.0 では、 andの宣言が必要typenameですが、 の宣言は必要ありません。Type1Type3Type2

gcc 4.8.1 ではtypenameの宣言が必要ですが、またはの宣言は必要ありType1ません。Type2Type3

struct C
{
    int f1();
    static int f2();
    int m;
};

template<int i>
struct S
{
    typedef int Type;
};

template<typename T>
struct B : C
{
};

template<typename T>
struct A : B<T>
{
    void f()
    {
        typedef typename S<sizeof(C::f1())>::Type Type1; // typename required
        typedef S<sizeof(C::f2())>::Type Type2; // typename not required
        typedef typename S<sizeof(C::m)>::Type Type3; // typename not required?
    }
};

template struct A<int>;

非静的メンバーへの呼び出しの暗黙のオブジェクト引数は であり、その型は依存しているため、typenameの宣言には図が必要です。[over.call.func] を参照してください。Type1(*this)

修飾されていない関数呼び出しでは、名前は->or.演算子によって修飾されず、primary-expression のより一般的な形式になります。名前は、関数呼び出しでの名前検索の通常の規則に従って、関数呼び出しのコンテキストで検索されます。そのルックアップによって見つかった関数宣言は、候補関数のセットを構成します。名前検索の規則により、候補関数のセットは、(1) 完全に非メンバー関数で構成されているか、(2) 完全に一部のクラス T のメンバー関数で構成されています。(1) の場合、引数リストは、呼び出しの式リスト。(2) の場合、引数リストは、修飾された関数呼び出しのように暗黙のオブジェクト引数の追加によって拡張された呼び出しの式リストです。キーワードthisがスコープ内にあり、クラスを参照している場合T、または の派生クラスのT場合、暗黙のオブジェクト引数は (*this)です。

このロジックに従うと、メンバーは静的であるため、typenameの宣言では必要ありません。式は非静的メンバーへの呼び出しではないため、の宣言にも必要Type2ありません。typenameType3

私はこれを読んだ:「テンプレート」と「タイプ名」のキーワードをどこに、なぜ入れなければならないのですか? .. [temp.dep.type] と [temp.dep.expr] のルールによって。式が依存しているかどうかを判断するときに、非静的メンバー関数名に特別な処理を施す必要があるかどうかを指定するものは何も見当たりません。規格はこれを指定していますか?

編集: [class.mfct.non-static] に基づくクラス メンバー アクセス式への変換に関する議論を削除しました - Casey の回答では、これについてより詳細に説明しています。

4

2 に答える 2

3

C非修飾名ルックアップによるフェーズ 1 ルックアップ中に解決される非依存名です。C::f1またC::f2、テンプレート ルックアップの最初のフェーズでも、修飾名ルックアップによって解決される非依存の名前です。Cこれは、 が のベースであるかどうかに関係なく当てはまりますA

質問で引用されている [class.mfct.non-static] のテキストは C++03 のもののようです。C++11 テキスト (9.3.1/3) には次のように書かれています。

クラスメンバーアクセス構文 (5.2.5) の一部ではなく、メンバー (5.3.1) へのポインターを形成するために使用されない id-expression (5.1) が、クラスのメンバーで使用Xれるthis場合使用される (5.1.1)、名前検索 (3.4) がid-expressionの名前を一部のクラスの非静的非型メンバーに解決するC場合、およびid-expression潜在的に評価される場合[emph. mine] またはCisXまたは の基本クラスであるX場合、id-expressionは、演算子の左側に(*this)(9.3.2) をpostfix-expressionとして使用して、クラス メンバー アクセス式 (5.2.5) に変換されます。.

C::f1は、 を使用できるコンテキストで評価される可能性があるため、に変換されます。明示的にテンプレート パラメータに依存するため、 14.6.2.1/5による不明な特殊化のメンバーです。[標準では、この「未知の特殊化のメンバー」という用語を使用して、テンプレートの何らかの特殊化のメンバーを示す可能性があるが、すべての特殊化に対してそうであることが証明されていない式を示します。]thisC::f1(*this).C::f1B<T>(*this).C::f1

は未知の特殊化(*this).C::f1のメンバーを表すため、14.6.2.2 /5による型依存のクラス メンバー アクセス式です。拡張により、14.6.2.2/1 ごとに型に依存します。 その後、14.6.2.3/2 ごとに値に依存します。-値依存の引数式を持つsimple-template-id - は、14.6.2.1/8 による依存型です。(*this).C::f1()sizeof((*this).C::f1())S<sizeof((*this).C::f1())>

S<sizeof((*this).C::f1())>依存しているので、

S<sizeof((*this).C::f1())>::Type

14.6.2/1 「... id-expression非修飾 IDが、テンプレート引数のいずれかがテンプレート パラメータに依存するテンプレートIDである場合」最後に、14.6/2 では、依存する名前が型を参照していることを示すためにキーワードを使用する必要があります。typename

typename S<sizeof((*this).C::f1())>::Type

それが推論の完全な連鎖だと思います。

編集:この答えは間違っているようです。「潜在的に評価される」という句は、3.2/2 の 1 つの定義規則 [basic.def.odr] で定義されています。

式は、未評価のオペランド (第 5 節) またはその部分式でない限り、評価される可能性があります。

C::f1この例では、確かに5.3.3/1 Sizeof [expr.sizeof]の評価されていないC::f1()オペランドである部分式です。sizeof

EDIT:式qualified-id()は現在ではないと思いますが、(1)クラステンプレートのメンバー関数内に表示され、(2)修飾されたIDが非依存の名前であり、オーバーロードセット一部のクラスの非静的メンバー関数、および (3) の型thisは依存型です。式の型を決定するには、13.3.1.1.1/3 ごとのオーバーロードの解決が必要です。thisこれは、参照先のクラスの型を決定せずにスコープ内にある場合は不可能thisです。

これは、次のように 14.6.2.1/5 [temp.dep.type] に箇条書きを追加することで実現できると思います。

  • 修飾されていない関数呼び出し (13.3.1.1.1/3 [over.call.func]) で使用される修飾 ID は、現在のインスタンス化または非依存の基本クラスではないクラスのメンバー関数のセットを示しますT。現在のインスタンス化に少なくとも 1 つの依存基底クラスがある場合。
于 2013-07-15T07:11:11.837 に答える