限定名查詢
一個限定名是指出現在作用域解析運算子 ::
右側的名稱(參見限定識別符號)。一個限定名可以引用
- 類成員(包括靜態和非靜態函式、型別、模板等),
- 名稱空間成員(包括另一個名稱空間),
- 列舉器。
如果 ::
的左側沒有任何內容,則查詢只考慮全域性名稱空間作用域中的宣告。這使得即使這些名稱被區域性宣告隱藏,也可以引用它們。
#include <iostream> namespace M { const char* fail = "fail\n"; } using M::fail; namespace N { const char* ok = "ok\n"; } using namespace N; int main() { struct std {}; std::cout << ::fail; // Error: unqualified lookup for 'std' finds the struct ::std::cout << ::ok; // OK: ::std finds the namespace std }
在對 ::
右側的名稱執行名稱查詢之前,必須完成對其左側名稱的查詢(除非使用了 decltype 表示式,或者左側沒有任何內容)。此查詢可以是限定的或非限定的,取決於該名稱左側是否還有另一個 ::
,它只考慮名稱空間、類型別、列舉和其特化是型別的模板。如果在左側找到的名稱未指定名稱空間、類、列舉或依賴型別,則程式格式錯誤。
struct A { static int n; }; int main() { int A; A::n = 42; // OK: unqualified lookup of A to the left of :: ignores the variable A b; // Error: unqualified lookup of A finds the variable A } template<int> struct B : A {}; namespace N { template<int> void B(); int f() { return B<0>::n; // Error: N::B<0> is not a type } }
當限定名用作宣告符時,在該限定名之後但在其之前的同一宣告符中使用的名稱的非限定查詢在成員的類或名稱空間的作用域中執行。
class X {}; constexpr int number = 100; struct C { class X {}; static const int number = 50; static X arr[number]; }; X C::arr[number], brr[number]; // Error: look up for X finds ::X, not C::X C::X C::arr[number], brr[number]; // OK: size of arr is 50, size of brr is 100
如果 ::
後面跟著字元 ~
,然後是識別符號(即,它指定了解構函式或偽解構函式),則該識別符號在與 ::
左側名稱相同的範圍內查詢。
struct C { typedef int I; }; typedef int I1, I2; extern int *p, *q; struct A { ~A(); }; typedef A AB; int main() { p->C::I::~I(); // The name I after ~ is looked up in the same scope as I before :: // (that is, within the scope of C, so it finds C::I) q->I1::~I2(); // The name I2 is looked up in the same scope as I1 // (that is, from the current scope, so it finds ::I2) AB x; x.AB::~AB(); // The name AB after ~ is looked up in the same scope as AB before :: // (that is, from the current scope, so it finds ::AB) }
列舉器如果左側名稱的查詢結果是列舉(無論是作用域內還是非作用域內),則右側的查詢結果必須是屬於該列舉的列舉器,否則程式格式錯誤。 |
(C++11 起) |
[編輯] 類成員
如果左側名稱的查詢結果是類/結構體或聯合名稱,則 ::
右側的名稱在該類的作用域中查詢(因此可能找到該類或其基類的成員宣告),但有以下例外情況:
- 解構函式如上所述查詢(在
::
左側名稱的作用域中)。 - 使用者定義轉換函式名稱中的轉換型別 ID 首先在該類的作用域中查詢。如果未找到,則在當前作用域中查詢該名稱。
- 模板引數中使用的名稱在當前作用域中查詢(而不是在模板名稱的作用域中)。
- using 宣告中的名稱也考慮被在同一作用域中宣告的變數、資料成員、函式或列舉器名稱隱藏的類/列舉名稱。
本節不完整 原因:上述內容的小例子 |
如果 ::
的右側命名了與左側相同的類,則該名稱指定該類的建構函式。這種限定名只能用於建構函式的宣告和繼承建構函式的 using 宣告中。在那些忽略函式名稱的查詢中(即,在 ::
左側查詢名稱時,在詳述型別說明符或基說明符中查詢名稱時),相同的語法解析為注入類名。
struct A { A(); }; struct B : A { B(); }; A::A() {} // A::A names a constructor, used in a declaration B::B() {} // B::B names a constructor, used in a declaration B::A ba; // B::A names the type A (looked up in the scope of B) A::A a; // Error: A::A does not name a type struct A::A a2; // OK: lookup in elaborated type specifier ignores functions // so A::A simply names the class A as seen from within the scope of A // (that is, the injected-class-name)
限定名稱查詢可用於訪問被巢狀宣告或派生類隱藏的類成員。對限定成員函式的呼叫絕不是虛的。
struct B { virtual void foo(); }; struct D : B { void foo() override; }; int main() { D x; B& b = x; b.foo(); // Calls D::foo (virtual dispatch) b.B::foo(); // Calls B::foo (static dispatch) }
[編輯] 名稱空間成員
如果 ::
左側的名稱引用名稱空間,或者 ::
左側沒有任何內容(在這種情況下它引用全域性名稱空間),則 ::
右側的名稱在該名稱空間的作用域中查詢,但以下情況除外:
- 模板引數中使用的名稱在當前作用域中查詢
namespace N { template<typename T> struct foo {}; struct X {}; } N::foo<X> x; // Error: X is looked up as ::X, not as N::X
在名稱空間 N
作用域內的限定查詢首先考慮位於 N
中的所有宣告以及位於 N
的內聯名稱空間成員中的所有宣告(並以傳遞方式,在其內聯名稱空間成員中)。如果該集合中沒有宣告,則它考慮位於 N
和 N
的所有傳遞性內聯名稱空間成員中找到的using 指令命名的所有名稱空間中的宣告。這些規則遞迴應用。
int x; namespace Y { void f(float); void h(int); } namespace Z { void h(double); } namespace A { using namespace Y; void f(int); void g(int); int i; } namespace B { using namespace Z; void f(char); int i; } namespace AB { using namespace A; using namespace B; void g(); } void h() { AB::g(); // AB is searched, AB::g found by lookup and is chosen AB::g(void) // (A and B are not searched) AB::f(1); // First, AB is searched. There is no f // Then, A, B are searched // A::f, B::f found by lookup // (but Y is not searched so Y::f is not considered) // Overload resolution picks A::f(int) AB::x++; // First, AB is searched. There is no x // Then A, B are searched. There is no x // Then Y and Z are searched. There is still no x: this is an error AB::i++; // AB is searched. There is no i // Then A, B are searched. A::i and B::i found by lookup: this is an error AB::h(16.8); // First, AB is searched. There is no h // Then A, B are searched. There is no h // Then Y and Z are searched // Lookup finds Y::h and Z::h. Overload resolution picks Z::h(double) }
允許多次找到相同的宣告。
namespace A { int a; } namespace B { using namespace A; } namespace D { using A::a; } namespace BD { using namespace B; using namespace D; } void g() { BD::a++; // OK: finds the same A::a through B and through D }
本節不完整 原因:N4861 6.5.3.2[namespace.qual] 的其餘部分,嘗試縮短它們的例子 |
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
CWG 215 | C++98 | :: 前的名稱必須是類名或名稱空間名稱,因此那裡不允許使用模板引數 |
該名稱必須指定一個類, 名稱空間或依賴型別 |
CWG 318 | C++98 | 如果 :: 的右側命名了相同的類作為左側,限定名總是 被認為是該類的建構函式 |
僅命名建構函式 當可接受時(例如,不在 詳述型別說明符) |