Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/language/injected-class-name"

From cppreference.com
< cpp‎ | language
m (Title)
(Added CWG issue #1004 DR, also reformatted code sections.)
Line 3: Line 3:
 
The injected-class-name is the name of a class within the scope of said class.
 
The injected-class-name is the name of a class within the scope of said class.
  
In a class template, the injected-class-name can be used either as a template name that refers to the current template, or as a class name that refers to the current instantiation.
+
In a {{rlp|class template}}, the injected-class-name can be used either as a template name that refers to the current template, or as a class name that refers to the current instantiation.
  
=== Explanation ===
+
===Explanation===
 
In a class scope, the name of the current class is treated as if it were a public member name; this is called ''injected-class-name''. The point of declaration of the name is immediately following the opening brace of the class definition.
 
In a class scope, the name of the current class is treated as if it were a public member name; this is called ''injected-class-name''. The point of declaration of the name is immediately following the opening brace of the class definition.
  
 
{{source|1=
 
{{source|1=
 
int X;
 
int X;
struct X {
+
 
     void f() {
+
struct X
         X* p; // OK. X refers to the injected-class-name
+
{
 +
     void f()
 +
    {
 +
         X* p;   // OK. X refers to the injected-class-name
 
         ::X* q; // Error: name lookup finds a variable name, which hides the struct name
 
         ::X* q; // Error: name lookup finds a variable name, which hides the struct name
 
     }
 
     }
Line 23: Line 26:
 
struct A {};
 
struct A {};
 
struct B : private A {};
 
struct B : private A {};
struct C : public B {
+
struct C : public B
     A* p; // Error: injected-class-name A is inaccessible
+
{
 +
     A* p;   // Error: injected-class-name A is inaccessible
 
     ::A* q; // OK, does not use the injected-class-name
 
     ::A* q; // OK, does not use the injected-class-name
 
};
 
};
 
}}
 
}}
  
=== In class template ===
+
===In class template===
 
Like other classes, class templates have an injected-class-name. The injected-class-name can be used as a template-name or a type-name.
 
Like other classes, class templates have an injected-class-name. The injected-class-name can be used as a template-name or a type-name.
  
Line 35: Line 39:
  
 
* it is followed by {{ttb|<}}<!-- intentionally differs from the standard, see cwg 1841 -->
 
* it is followed by {{ttb|<}}<!-- intentionally differs from the standard, see cwg 1841 -->
* <!-- cwg 1004 -->it is used as a template argument that corresponds to a template template parameter
+
* it is used as a {{rlp|template parameters#Template template arguments|template template argument}}
* <!-- cwg 602 -->it is the final identifier in the elaborated class specifier of a friend class template declaration.
+
* it is the final identifier in the {{rlp|elaborated type specifier|elaborated class specifier}} of a friend class template declaration.
  
 
Otherwise, it is treated as a type-name, and is equivalent to the template-name followed by the template-parameters of the class template enclosed in {{ttb|<>}}.
 
Otherwise, it is treated as a type-name, and is equivalent to the template-name followed by the template-parameters of the class template enclosed in {{ttb|<>}}.
  
 
{{source|1=
 
{{source|1=
template <template <class, class> class> struct A;
+
template<template<class, class> class>
 +
struct A;
  
 
template<class T1, class T2>
 
template<class T1, class T2>
struct X {
+
struct X
     X<T1, T2>* p; // OK, X is treated as a template-name
+
{
 +
     X<T1, T2>* p;   // OK, X is treated as a template-name
 +
   
 
     using a = A<X>; // 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>
 
     template<class U1, class U2>
 
     friend class X; // OK, X is treated as a template-name
 
     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>
+
   
 +
     X* q;           // OK, X is treated as a type-name, equivalent to X<T1, T2>
 
};
 
};
 
}}
 
}}
  
Within the scope of a class template specialization or partial specialization, when the injected-class-name is used as a type-name, it is equivalent to the template-name followed by the template-arguments of the class template specialization or partial specialization enclosed in {{ttb|<>}}.
+
Within the scope of a class {{rlp|template specialization}} or {{rlp|partial specialization}}, when the injected-class-name is used as a type-name, it is equivalent to the template-name followed by the template-arguments of the class template specialization or partial specialization enclosed in {{ttb|<>}}.
  
 
{{source|1=
 
{{source|1=
 
template<>
 
template<>
struct X<void, void> {
+
struct X<void, void>
 +
{
 
     X* p; // OK, X is treated as a type-name, equivalent to X<void, void>
 
     X* p; // OK, X is treated as a type-name, equivalent to X<void, void>
 +
   
 
     template<class, class>
 
     template<class, class>
 
     friend class X; // OK, X is treated as a template-name (same as in primary template)
 
     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
 
     X<void, void>* q; // OK, X is treated as a template-name
 
};
 
};
 +
 
template<class T>
 
template<class T>
struct X<char, T> {
+
struct X<char, T>
 +
{
 
     X* p, q; // OK, X is treated as a type-name, equivalent to 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
 
     using r = X<int, int>; // OK, can be used to name another specialization
 
};
 
};
Line 73: Line 88:
  
 
{{source|1=
 
{{source|1=
template<> class X<int, char> {
+
template<>
     class B {
+
class X<int, char>
         X a; // meaning X<int, char>
+
{
         template<class,class> friend class X; // meaning ::X
+
     class B
 +
    {
 +
         X a;           // meaning X<int, char>
 +
       
 +
         template<class, class>
 +
        friend class X; // meaning ::X
 
     };
 
     };
 
};
 
};
template <class T> struct Base {
+
 
 +
template<class T>
 +
struct Base
 +
{
 
     Base* p; // OK: Base means Base<T>
 
     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>
 +
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 { };
+
 
 +
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
 
Third<Derived<int>> t; // OK: default argument uses injected-class-name as a template
 
}}
 
}}
Line 92: Line 122:
  
 
{{source|1=
 
{{source|1=
template <class T> struct Base {};
+
template<class T>
template <class T> struct Derived: Base<int>, Base<char> {
+
struct Base {};
     typename Derived::Base b; // error: ambiguous
+
 
 +
template<class T>
 +
struct Derived: Base<int>, Base<char>
 +
{
 +
     typename Derived::Base b;         // error: ambiguous
 
     typename Derived::Base<double> d; // OK
 
     typename Derived::Base<double> d; // OK
 
};
 
};
 
}}
 
}}
  
=== injected-class-name and constructors ===
+
===injected-class-name and constructors===
 
Constructors do not have names, but the injected-class-name of the enclosing class is considered to name a constructor in constructor declarations and definitions.
 
Constructors do not have names, but the injected-class-name of the enclosing class is considered to name a constructor in constructor declarations and definitions.
  
<!-- cwg 147 -->In a qualified name {{tt|C::D}}, if
+
In a qualified name {{tt|C::D}}, if
  
* name lookup does not ignore function names<!-- cwg 318, cwg 1310 -->, and
+
* name lookup does not ignore function names<!-- cwg 1310 -->, and
 
* lookup of {{tt|D}} in the scope of the class {{tt|C}} finds its injected-class-name
 
* lookup of {{tt|D}} in the scope of the class {{tt|C}} finds its injected-class-name
  
Line 110: Line 144:
  
 
{{source|1=
 
{{source|1=
struct A {
+
struct A
 +
{
 
     A();
 
     A();
 
     A(int);
 
     A(int);
     template<class T> A(T) {}
+
   
 +
     template<class T>
 +
    A(T) {}
 
};
 
};
 
using A_alias = A;
 
using A_alias = A;
Line 121: Line 158:
 
template A::A(double);
 
template A::A(double);
  
struct B : A {
+
struct B : A
 +
{
 
     using A_alias::A;
 
     using A_alias::A;
 
};
 
};
  
A::A a; // Error: A::A is considered to name a constructor, not a type
+
A::A a;         // Error: A::A is considered to name a constructor, not a type
 
struct A::A a2; // OK, same as 'A a2;'
 
struct A::A a2; // OK, same as 'A a2;'
B::A b; // OK, same as 'A b;'
+
B::A b;         // OK, same as 'A b;'
 
}}
 
}}
 +
 +
===Defect reports===
 +
{{dr list begin}}
 +
{{dr list item|wg=cwg|dr=1004|std=C++98|before=an injected-class-name could not<br>be a template template argument|after=allowed, it refers to the class<br>template itself in this case}}
 +
{{dr list end}}
  
 
{{langlinks|es|ja|zh}}
 
{{langlinks|es|ja|zh}}

Revision as of 22:14, 5 May 2022

 
 
C++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++17*)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
explicit (C++11)
static

Special member functions
Templates
Miscellaneous
 
 

The injected-class-name is the name of a class within the scope of said class.

In a class template, the injected-class-name can be used either as a template name that refers to the current template, or as a class name that refers to the current instantiation.

Contents

Explanation

In a class scope, the name of the current class is treated as if it were a public member name; this is called injected-class-name. The point of declaration of the name is immediately following the opening brace of the class definition.

int X;
 
struct X
{
    void f()
    {
        X* p;   // OK. X refers to the injected-class-name
        ::X* q; // Error: name lookup finds a variable name, which hides the struct name
    }
};

Like other members, injected-class-names are inherited. In the presence of private or protected inheritance, the injected-class-name of an indirect base class might end up being inaccessible in a derived class.

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
};

In class template

Like other classes, class templates have an injected-class-name. The injected-class-name can be used as a template-name or a type-name.

In the following cases, the injected-class-name is treated as a template-name of the class template itself:

Otherwise, it is treated as a type-name, and is equivalent to the template-name followed by the template-parameters of the class template enclosed in <>.

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>
};

Within the scope of a class template specialization or partial specialization, when the injected-class-name is used as a type-name, it is equivalent to the template-name followed by the template-arguments of the class template specialization or partial specialization enclosed in <>.

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
};

The injected-class-name of a class template or class template specialization can be used either as a template-name or a type-name wherever it is in scope.

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

A lookup that finds an injected-class-name can result in an ambiguity in certain cases (for example, if it is found in more than one base class). If all of the injected-class-names that are found refer to specializations of the same class template, and if the name is used as a template-name, the reference refers to the class template itself and not a specialization thereof, and is not ambiguous.

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
};

injected-class-name and constructors

Constructors do not have names, but the injected-class-name of the enclosing class is considered to name a constructor in constructor declarations and definitions.

In a qualified name C::D, if

  • name lookup does not ignore function names, and
  • lookup of D in the scope of the class C finds its injected-class-name

the qualified name is always considered to name C's constructor. Such a name can only be used in the declaration of a constructor (e.g. in a friend constructor declaration, a constructor template specialization, constructor template instantiation, or constructor definition) or be used to inherit constructors(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;'

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
CWG 1004 C++98 an injected-class-name could not
be a template template argument
allowed, it refers to the class
template itself in this case