7

gcc 5.0 と clang 3.6 の両方typenameで、次の例のキーワードが必要です。

template<typename T>
struct B
{
    typedef int Type;
};

template<int n>
struct A
{
    typedef typename B<decltype(throw (int*)n)>::Type Throw;
    typedef typename B<decltype(delete (int*)n)>::Type Delete;
};

これは、C++11 標準の次の文言でカバーされています。

[除く]/2

throw 式は void 型です。

[expr.delete]/1

オペランドには、オブジェクト型へのポインター、またはオブジェクト型へのポインターへの単一の非明示的な変換関数を持つクラス型が必要です。結果の型は void です。

したがって、両方のケースでdecltype生成されると想定しています。void

[expr.const]/2

conditional-expression は、潜在的に評価される部分式として次のいずれかを含まない限り、コア定数式です。

  • 新しい式

  • スロー式

throwこれは、またはのいずれかを含む式がdelete定数式ではないことを示唆しています。

[温度依存タイプ]/8

ある場合、型は従属です。

  • テンプレート名がテンプレート パラメータであるか、いずれかのテンプレート引数が依存型または型依存または値依存の式である simple-template-id

  • で表されdecltype(expression)、式は型に依存します

SoB<decltype(..)>は、式が型依存の場合にのみ依存します。

[温度.dep.expr]/4

次の形式の式は型に依存しません (式の型は依存できないため)。

delete cast-expression
throw assignment-expression

これは、どちらの式も型に依存しないことを示唆しています。

gcc と clang はどちらも間違っていますか?

4

1 に答える 1

7

typenameが必要な場合に戻りましょう。§14.6 [temp.res]/p3、すべての引用は N4140 からのものです。

修飾 IDが現在のインスタンス化 (14.6.2.1) のメンバーではない型を参照することを意図しており、その ネストされた名前指定子が依存型を参照する場合、型名typenameを形成するキーワードをプレフィックスとして付ける必要があります。-指定子.

この場合の修飾 IDB<decltype(throw (int*)n)>::Type(およびdelete分析がまったく同じであるバージョン) です。nested-name-specifierまたはが依存型を参照する場合は、これtypenameが必要です。B<decltype(throw (int*)n)>::

§14.6.2.1 [temp.dep.type]/p8 は、6 つの無関係な箇条書きを省略して、次のように述べています。

ある場合、型は従属です。

[...]

(8.7) —テンプレート名がテンプレート パラメータであるか、いずれかのテンプレート引数が依存型または型依存または値依存の式であるsimple-template-id 、または

(8.8) — decltype(expression)で示されます。は型に依存します (14.6.2.2)。

B<decltype(throw (int*)n)>simple-template-idです。テンプレート名Bはテンプレート パラメータではありません。唯一のテンプレート引数decltype(throw (int*)n)は式ではないため、依存型であるB<decltype(throw (int*)n)>場合にのみdecltype(throw (int*)n)依存します。decltype(throw (int*)n)、順番に、箇条書き 8.8 に従って、throw (int*)n型に依存する場合にのみ依存します。しかし、§14.6.2.2 [temp.dep.expr]/p4 によると、次のことがわかっています。

次の形式の式は型に依存しません (式の型は依存できないため)。

[...]

::opt delete キャスト式

[...]

throw 代入式オプション

[...]

したがって、throw (int*)nは型依存でdecltype(throw (int*)n)はなく、依存型でもB<decltype(throw (int*)n)>なく、依存型でもないので、 にtypenameは必要ありませんB<decltype(throw (int*)n)>::Type。そうです、これはコンパイラのバグです。

于 2014-12-30T23:33:28.360 に答える