注入類名
來自 cppreference.com
注入類名是類在其作用域內的非限定名稱。
在類模板中,注入類名既可以用作引用當前模板的模板名,也可以用作引用當前例項化的類名。
目錄 |
[編輯] 解釋
在類作用域中,當前類的類名或當前類模板的模板名被視為公共成員名;這被稱為注入類名。該名稱的宣告點緊接在類(模板)定義的開大括號之後。
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 } };
與其他成員一樣,注入類名是可繼承的。在私有或保護繼承存在的情況下,間接基類的注入類名可能在派生類中變得不可訪問。
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
的建構函式。這樣的名稱只能用於建構函式的宣告中(例如在友元建構函式宣告、建構函式模板特化、建構函式模板例項化或建構函式定義中)或用於繼承建構函式(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++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
CWG 1004 | C++98 | 注入類名不能 作為模板模板實參 |
允許,在此情況下它指的是類 模板本身 |
CWG 2637 | C++98 | 整個模板-id可以是注入類名 | 只有模板名可以 |