web-dev-qa-db-ja.com

ネストされたタイプの基本クラスに「typename」が必要でないのはなぜですか?

依存型が基本クラスとして表示されるときにtypenameを追加する必要がないことを知って、私は非常に驚いています。

struct B {};

struct wr
{ typedef B type; };

template<class T>
struct A : T::type
{};

int main()
{
    A<wr> a;
    (void)a;
}

T::typeの前にtypenameが必要ないのはなぜですか?

25
Peregring-lk

他の人が指摘したように、それは特別なケースです。これに関する標準を引用するには:

[temp.res]

5 class-or-decltypeまたはelaborated-type-specifierで名前として使用される修飾名は、typenameキーワードを使用せずに、暗黙的に型に名前を付けるものと見なされます。テンプレートパラメータに依存するネストされた名前指定子がすぐに含まれるネストされた名前指定子では、typenameキーワードを使用せずに、識別子またはsimple-template-idが暗黙的に型に名前を付けると想定されます。 [注:typenameキーワードは、これらの構文の構文では許可されていません。 —メモ終了]

そしてC++ 20が来ると、typenameの必要性にはさらに多くの例外があります。

T::typeの前にtypenameが必要ないのはなぜですか?

値から継承できないからです。 typenameを使用して、指定されたネストされた識別子が型であることをコンパイラーに伝えますが、継承の場合はそれがとにかく当てはまる必要があるため、省略できます。そのため、言語はtypename-ベース指定子のルール。 From cppreference (強調は私のもの):

依存名のtypename曖昧性解消子

エイリアステンプレートを含むテンプレートの宣言または定義では、現在のインスタンス化のメンバーではなく、テンプレートパラメーターに依存する名前は、キーワードtypenameが使用されているかそれがすでに型名として確立されていない限り、例えばtypedef宣言を使用するか、基本クラスに名前を付けるために使用されます

typenameを省略できる場所が増えることに注意してください。 P0634 を参照してください。

19
lubgr

typenameを使用する必要があるのは、コンパイラにタイプではなくタイプを期待するように指示する必要がある場合のみです。

継承できるのは型のみなので、あいまいさはなく、typenameは不要です。

5
Bathsheba