Injected-class-name
注入されたクラス名は、そのクラスのスコープ内におけるクラスの非修飾名です。
クラステンプレートにおいて、注入されたクラス名は、現在のテンプレートを参照するテンプレート名として、または現在のインスタンス化を参照するクラス名として使用できます。
目次 |
説明
クラス スコープ において、現在のクラスのクラス名または現在のクラステンプレートのテンプレート名は、あたかも公開メンバ名であるかのように扱われる。これは injected-class-name と呼ばれる。この名前の宣言点は、クラス(テンプレート)定義の開始ブレース直後である。
int X; struct X { void f() { X* p; // OK: X は注入されたクラス名 ::X* q; // エラー: 名前探索が変数名を発見し、構造体名を隠蔽する } }; template<class T> struct Y { void g() { Y* p; // OK: Y は注入されたクラス名 Y<T>* q; // OK: Y は注入されたクラス名だが、Y<T> は注入されたクラス名ではない } };
他のメンバと同様に、注入クラス名は継承されます。非公開または限定公開の継承が存在する場合、間接基底クラスの注入クラス名が派生クラスでアクセス不能になる可能性があります。
struct A {}; struct B : private A {}; struct C : public B { A* p; // エラー: 注入されたクラス名Aはアクセス不可 ::A* q; // OK, 注入されたクラス名を使用しない };
クラステンプレート内
クラステンプレートの注入されたクラス名は、テンプレート名または型名として使用できます。
以下の場合、注入されたクラス名はクラステンプレート自体のテンプレート名として扱われます:
-
これは
<が後に続きます。 - これは template template argument として使用されます。
- これは elaborated class specifier 内の最終識別子であり、フレンドクラステンプレート宣言の一部です。
それ以外の場合、型名として扱われ、クラステンプレートのテンプレートパラメータを
<>
で囲んだテンプレート名と等価になります。
template<template<class, class> class> struct A; template<class T1, class T2> struct X { X<T1, T2>* p; // OK、Xはテンプレート名として扱われる using a = A<X>; // OK、Xはテンプレート名として扱われる template<class U1, class U2> friend class X; // OK、Xはテンプレート名として扱われる X* q; // OK、Xは型名として扱われ、X<T1, T2>と等価 };
クラスの
テンプレート特殊化
または
部分特殊化
のスコープ内で、注入されたクラス名が型名として使用される場合、それはテンプレート名に続けてクラステンプレートの特殊化または部分特殊化のテンプレート引数を
<>
で囲んだものと等価です。
template<> struct X<void, void> { X* p; // OK: Xは型名として扱われ、X<void, void>と等価 template<class, class> friend class X; // OK: Xはテンプレート名として扱われる(プライマリテンプレートと同じ) X<void, void>* q; // OK: Xはテンプレート名として扱われる }; template<class T> struct X<char, T> { X* p, q; // OK: Xは型名として扱われ、X<char, T>と等価 using r = X<int, int>; // OK: 他の特殊化を指定するために使用可能 };
クラステンプレートまたはクラステンプレート特殊化の注入されたクラス名は、それがスコープ内にある場所では、テンプレート名または型名のいずれかとして使用できます。
template<> class X<int, char> { class B { X a; // X<int, char> を意味する template<class, class> friend class X; // ::X を意味する }; }; template<class T> struct Base { Base* p; // OK: Base は Base<T> を意味する }; template<class T> struct Derived : public Base<*T*> { typename Derived::Base* p; // OK: Derived::Base は Derived<T>::Base を意味し、 // これは Base<T*> である }; template<class T, template<class> class U = T::template Base> struct Third {}; Third<Derived<int>> t; // OK: デフォルト引数は注入されたクラス名をテンプレートとして使用する
注入されたクラス名を検索するルックアップは、特定の場合に曖昧さを引き起こすことがあります(例えば、複数の基底クラスで見つかった場合)。見つかったすべての注入されたクラス名が同じクラステンプレートの特殊化を参照しており、かつその名前がテンプレート名として使用される場合、その参照はクラステンプレート自体を指し、その特殊化を参照するものではなく、曖昧ではありません。
template<class T> struct Base {}; template<class T> struct Derived: Base<int>, Base<char> { typename Derived::Base b; // エラー: 曖昧 typename Derived::Base<double> d; // OK };
注入クラス名とコンストラクタ
コンストラクタには名前はありませんが、囲んでいるクラスの注入クラス名は、コンストラクタの宣言と定義においてコンストラクタを命名するものと見なされます。
修飾名
C::D
において、もし
- name lookup は関数名を無視せず、また
-
CクラスのスコープにおけるDのlookupは、その注入されたクラス名を見つける
修飾名は常に
C
のコンストラクタを指すものと見なされます。このような名前はコンストラクタの宣言(例:フレンドコンストラクタ宣言、コンストラクタテンプレートの特殊化、コンストラクタテンプレートのインスタンス化、またはコンストラクタ定義)でのみ使用できます
またはコンストラクタの継承に使用できます
(C++11以降)
。
struct A { A(); A(int); template<class T> A(T) {} }; using A_alias = A; A::A() {} A_alias::A(int) {} template A::A(double); struct B : A { using A_alias::A; }; A::A a; // エラー: A::Aは型ではなくコンストラクタを指すとみなされる struct A::A a2; // OK、'A a2;'と同じ B::A b; // OK、'A b;'と同じ
不具合報告
以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。
| DR | 適用対象 | 公開時の動作 | 正しい動作 |
|---|---|---|---|
| CWG 1004 | C++98 |
注入クラス名はテンプレートテンプレート引数に
できなかった |
許可され、この場合クラステンプレート自体を
参照する |
| CWG 2637 | C++98 | テンプレートID全体が注入クラス名になり得た | テンプレート名のみが可能 |