7

次の例では、 のインスタンス化を引き起こすAメンバ typedefがあります。InstantiateB<A>

template<typename T>
struct B
{
    typedef typename T::Before Before; // ok
    typedef typename T::After After; // error: no type named 'After' in 'A<int>'
};

template<typename T>
struct A
{
    typedef int Before;
    typedef typename B<A>::After Instantiate;
    typedef int After;
};

template struct A<int>; // instantiate A<int>

私が試したすべてのコンパイラは、表示されているA::Beforeが表示されA::Afterていないと報告しています。この動作は標準に準拠していますか? もしそうなら、標準は のAインスタンス化中にどの名前を表示する必要があるかをどこで指定していますB<A>か?

従属名が「テンプレートのインスタンス化の時点で検索される」場合、これは ? などのテンプレート パラメータによって修飾された名前のシナリオで何を意味しますT::Afterか?

編集: A がテンプレートでない場合、同じ動作が発生することに注意してください:

template<typename T>
struct B
{
    typedef typename T::Before Before; // ok
    typedef typename T::After After; // error: no type named 'After' in 'A'
};

struct A
{
    typedef int Before;
    typedef B<A>::After Instantiate;
    typedef int After;
};

.. そして G++ は以下を受け入れますが、Clang は受け入れません:

template<typename T>
struct B
{
    static const int value = 0;
    static const int i = T::value; // clang error: not a constant expression
};

struct A
{
    static const int value = B<A>::value;
};

編集: C++03 標準を読んだ後:

[temp.dep.type] テンプレート パラメーターの場合、型は依存します

したがってT、依存しています。

[temp.res] テンプレート定義で使用される名前の宣言を検索する場合、通常の検索規則が非依存の名前に使用されます。テンプレート パラメータに依存する名前の検索は、実際のテンプレート引数が判明するまで延期されます。

したがって、 のルックアップはT::After、 の引数が判明するまで延期さTれます。

[temp.inst] クラス テンプレートの特殊化が明示的にインスタンス化されていない限り ... 完全に定義されたオブジェクト型を必要とするコンテキストで特殊化が参照されると、クラス テンプレートの特殊化は暗黙的にインスタンス化されます。

したがって、の宣言にA<int>::Instantiateは、のインスタンス化が必要ですB<A>(ネストされた名前指定子で使用されるため)。

A<int>::Afterの宣言の時点では見えないA<int>::Instantiateため、コンパイラの動作は理にかなっていますが、この動作を明示的に説明している C++03 は見たことがありません。最も近いのは、このややあいまいな段落でした。

[temp.dep.res] 依存する名前の解決では、次のソースからの名前が考慮されます。

— テンプレートの定義時に表示される宣言。

4

2 に答える 2

4

有効かどうかtypename T::Beforeは、仕様で明示的に述べられていません。これは欠陥レポートの対象です (標準を読むと非常に合理的に禁止されているため): http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#287 .

無効であるかどうかtypename T::Afterは、仕様によって真であると非常に合理的に読み取ることができ、実際にはかなり理にかなっています (そして、前述の DR は依然としてそれを不適切な形式のままにしています)。メンバーがまだ宣言されていない期間中にA<Foo>別のクラスを参照し、 への参照を戻すclass のインスタンス化があるためです。非テンプレートの場合も同様に形式が正しくありません (テンプレートを扱っていることを少し「忘れる」ようにしてください: 確かに、テンプレートが完全に解析された後にルックアップが行われますが、テンプレートの特定のインスタンス化の後ではありません。が完全に作成され、実際に参照を行うのはそのインスタンス化です!)。A<Bar>BazA<Foo>::BarB<A>::AfterA

struct A {
   typedef int Foo;
   typedef A::Foo Bar; // valid
   typedef A::Baz Lulz; // *not* valid
   typedef int Baz; 
};
于 2013-07-05T22:58:13.073 に答える
2

T::BeforeT::After[temp.dep.type]/8 および /5 による依存名です。

依存名は、「テンプレート定義のコンテキストとインスタンス化ポイントのコンテキストの両方で、テンプレートのインスタンス化のポイント (14.6.4.1) で」検索されます。[温度差]/1

私はこれを次のように解釈します: テンプレートがインスタンス化されるときに検索されます。彼らはどこで調べましたか?テンプレート定義のコンテキストとインスタンス化ポイントのコンテキスト。

[temp.dep.type]/7 一方、次のように述べています。

テンプレート引数の特定のセットに対して、修飾 ID またはクラス メンバー アクセス式を使用して現在のインスタンス化のメンバーを参照するテンプレートの特殊化がインスタンス化される場合、修飾IDまたはクラス メンバー アクセス式の名前は次のようになります。テンプレートのインスタンス化コンテキストで検索されました。

[temp.point]/7インスタンス化コンテキストを次のように定義します。

テンプレート引数に依存する式のインスタンス化コンテキストは、同じ翻訳単位内のテンプレート特殊化のインスタンス化のポイントより前に宣言された外部リンケージを持つ宣言のセットです。

したがって、インスタンス化のポイントが何であるかを知る必要があります。

[温度ポイント]/4

クラス テンプレートの特殊化 [...] の場合、特殊化が別のテンプレートの特殊化内から参照されるために暗黙的にインスタンス化される場合、特殊化が参照されるコンテキストがテンプレート パラメーターに依存する場合、および特殊化が前にインスタンス化されない場合囲んでいるテンプレートのインスタンス化に対して、インスタンス化のポイントは、囲んでいるテンプレートのインスタンス化のポイントの直前です。

注入されたクラス名Aは、間違いなくのテンプレート パラメータに依存する(一般的な用語として)コンテキストですがA、名前A自体は依存名ではありません。Johannes Schaubによる訂正:従属名です[temp.local]/1 および [temp.dep.type]/8 を参照 =>A依存型です。

したがって、この条件 満たされていないB<A>ため、 の前にインスタンス化する必要がありますA<int>

于 2013-07-04T23:07:39.943 に答える