名前空間
変種
操作

注入されたクラス名

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

注入されたクラス名とは、そのクラスのスコープ内における、修飾されていないクラス名のことです。

クラステンプレートにおいて、注入されたクラス名は、現在のテンプレートを参照するテンプレート名としても、現在のインスタンス化を参照するクラス名としても使用できます。

目次

[編集] 説明

クラスのスコープ内では、現在のクラスのクラス名または現在のクラステンプレートのテンプレート名が、あたかもpublicなメンバ名であるかのように扱われます。これは「注入されたクラス名」と呼ばれます。この名前の宣言点は、クラス(テンプレート)定義の開始ブレースの直後です。

int X;
 
struct X
{
    void f()
    {
        X* p;   // OK, X is an injected-class-name
        ::X* q; // Error: name lookup finds a variable name, which hides the struct name
    }
};
 
template<class T>
struct Y
{
    void g()
    {
        Y* p;    // OK, Y is an injected-class-name
        Y<T>* q; // OK, Y is an injected-class-name, but Y<T> is not
    }
};

他のメンバと同様に、注入されたクラス名も継承されます。privateまたはprotected継承の場合、間接的な基底クラスの注入されたクラス名が、派生クラスでアクセス不能になる可能性があります。

struct A {};
struct B : private A {};
struct C : public B
{
    A* p;   // Error: injected-class-name A is inaccessible
    ::A* q; // OK, does not use the injected-class-name
};

[編集] クラステンプレート内

クラステンプレートの注入されたクラス名は、テンプレート名または型名として使用できます。

以下のケースでは、注入されたクラス名はクラステンプレート自体のテンプレート名として扱われます。

それ以外の場合は、型名として扱われ、<>で囲まれたテンプレートパラメータを持つクラステンプレートのテンプレート名と同等になります。

template<template<class, class> class>
struct A;
 
template<class T1, class T2>
struct X
{
    X<T1, T2>* p;   // OK, X is treated as a template-name
 
    using a = A<X>; // OK, X is treated as a template-name
 
    template<class U1, class U2>
    friend class X; // OK, X is treated as a template-name
 
    X* q;           // OK, X is treated as a type-name, equivalent to X<T1, T2>
};

クラステンプレートの特殊化または部分特殊化のスコープ内では、注入されたクラス名が型名として使用される場合、<>で囲まれたクラステンプレート特殊化または部分特殊化のテンプレート引数を持つテンプレート名と同等になります。

template<>
struct X<void, void>
{
    X* p; // OK, X is treated as a type-name, equivalent to X<void, void>
 
    template<class, class>
    friend class X; // OK, X is treated as a template-name (same as in primary template)
 
    X<void, void>* q; // OK, X is treated as a template-name
};
 
template<class T>
struct X<char, T>
{
    X* p, q; // OK, X is treated as a type-name, equivalent to X<char, T>
 
    using r = X<int, int>; // OK, can be used to name another specialization
};

クラステンプレートまたはクラステンプレート特殊化の注入されたクラス名は、スコープ内であればテンプレート名としても型名としても使用できます。

template<>
class X<int, char>
{
    class B
    {
        X a;            // meaning X<int, char>
 
        template<class, class>
        friend class X; // meaning ::X
    };
};
 
template<class T>
struct Base
{
    Base* p; // OK: Base means Base<T>
};
 
template<class T>
struct Derived : public Base<T*>
{
    typename Derived::Base* p; // OK: Derived::Base means Derived<T>::Base,
                               // which is Base<T*>
};
 
template<class T, template<class> class U = T::template Base>
struct Third {};
 
Third<Derived<int>> t; // OK: default argument uses injected-class-name as a template

注入されたクラス名を見つける名前探索は、特定のケース(例えば、複数の基底クラスで見つかった場合)で曖昧さを生じさせる可能性があります。見つかったすべての注入されたクラス名が同じクラステンプレートの特殊化を参照しており、その名前がテンプレート名として使用されている場合、その参照は特殊化ではなくクラステンプレート自体を参照し、曖昧ではありません。

template<class T>
struct Base {};
 
template<class T>
struct Derived: Base<int>, Base<char>
{
    typename Derived::Base b;         // error: ambiguous
    typename Derived::Base<double> d; // OK
};

[編集] 注入されたクラス名とコンストラクタ

コンストラクタは名前を持ちませんが、囲むクラスの注入されたクラス名は、コンストラクタの宣言と定義においてコンストラクタを命名するものと見なされます。

修飾名 `C::D` において、もし

  • 名前探索が関数名を無視せず、かつ
  • クラス `C` のスコープ内での `D` の探索がその注入されたクラス名を見つけた場合

その修飾名は常に `C` のコンストラクタを命名するものと見なされます。そのような名前は、コンストラクタの宣言(例: friendコンストラクタ宣言、コンストラクタテンプレート特殊化、コンストラクタテンプレートインスタンス化、またはコンストラクタ定義)またはコンストラクタの継承(since 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;         // Error: A::A is considered to name a constructor, not a type
struct A::A a2; // OK, same as 'A a2;'
B::A b;         // OK, same as 'A b;'

[編集] 不具合報告

以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
CWG 1004 C++98 注入されたクラス名は
テンプレートテンプレート引数にできませんでした。
この場合、クラス
テンプレート自体を参照する。
CWG 2637 C++98 テンプレートID全体が注入されたクラス名になる可能性がありました。 テンプレート名のみが
English 日本語 中文(简体) 中文(繁體)