Unqualified name lookup
For an unqualified name, that is a name that does not appear to the right of a scope resolution operator ::
, name lookup examines the scopes
::
For the purpose of unqualified name lookup, all declarations from a namespace nominated by a using directive
Unqualified name lookup of the name used to the left of the function-call operator (and, equivalently, operator in an expression) is described in argument-dependent lookup.
File scope
For a name used in global (top-level namespace) scope, outside of any function, class, or user-declared namespace, the global scope before the use of the name is examined:
int n = 1; // declaration of n int x = n + 1; // OK: lookup finds ::n int z = y - 1; // Error: lookup fails int y = 2; // declaration of y
Namespace scope
For a name used in a user-declared namespace outside of any function or class, this namespace is searched before the use of the name, then the namespace enclosing this namespace before the declaration of this namespace, etc until the global namespace is reached.
int n = 1; // declaration namespace N { int m = 2; namespace Y { int x = n; // OK, lookup finds ::n int y = m; // OK, lookup finds ::N::m int z = k; // Error: lookup fails } int k = 3; }
Definition outside of its namespace
For a name used in the definition of a namespace-member variable outside the namespace, lookup proceeds the same way as for a name used inside the namespace:
namespace X { extern int x; // declaration, not definition int n = 1; // found 1st } int n = 2; // found 2nd int X::x = n; // finds X::n, sets X::x to 1
Non-member function definition
For a name used in the definition of a function, either in its body or as part of default argument, where the function is a member of user-declared or global namespace, the block in which the name is used is searched before the use of the name, then the enclosing block is searched before the start of that block, etc, until reaching the block that is the function body. Then the namespace in which the function is declared is searched until the definition (not necessarily the declaration) of the function that uses the name, then the enclosing namespaces, etc.
namespace A { namespace N { void f(); int i = 3; // found 3rd (if 2nd is not present) } int i = 4; // found 4th (if 3rd is not present) } int i = 5; // found 5th (if 4th is not present) void A::N::f() { int i = 2; // found 2nd (if 1st is not present) while (true) { int i = 1; // found 1st: lookup is done std::cout << i; } } // int i; // not found namespace A { namespace N { // int i; // not found } }
Class definition
For a name used anywhere in class definition
For a friend declaration, the lookup to determine whether it refers to a previously declared entity proceeds as above except that it stops after the innermost enclosing namespace.
namespace M { // const int i = 1; // never found class B { // static const int i = 3; // found 3rd (but will not pass access check) }; } // const int i = 5; // found 5th namespace N { // const int i = 4; // found 4th class Y : public M::B { // static const int i = 2; // found 2nd class X { // static const int i = 1; // found 1st int a[i]; // use of i // static const int i = 1; // never found }; // static const int i = 2; // never found }; // const int i = 4; // never found } // const int i = 5; // never found
Injected class name
For the name of a class or class template used within the definition of that class or template or derived from one, unqualified name lookup finds the class that's being defined as if the name was introduced by a member declaration (with public member access). For more detail, see injected-class-name
Member function definition
For a name used inside a member function body, a default argument of a member function, exception specification of a member function, or a default member initializer, the scopes searched are the same as in class definition
class B { // int i; // found 3rd }; namespace M { // int i; // found 5th namespace N { // int i; // found 4th class X : public B { // int i; // found 2nd void f(); // int i; // found 2nd as well }; // int i; // found 4th } } // int i; // found 6th void M::N::X::f() { // int i; // found 1st i = 16; // int i; // never found } namespace M { namespace N { // int i; // never found } }
- Either way, when examining the bases from which the class is derived, the following rules, sometime referred to as dominance in virtual inheritance
A member name found in a sub-object B hides the same member name in any sub-object A if A is a base class sub-object of B . (Note that this does not hide the name in any additional, non-virtual, copies of A on the inheritance lattice that aren't bases of B
|
(until C++11) |
A lookup set
C is the class in whose scope the name was used, C is examined first. If the list of declarations in C is empty, lookup set is built for each of its direct bases Bi (recursively applying these rules if Bi has its own bases). Once built, the lookup sets for the direct bases are merged into the lookup set in C as follows:
|
(since C++11) |
struct X { void f(); }; struct B1: virtual X { void f(); }; struct B2: virtual X {}; struct D : B1, B2 { void foo() { X::f(); // OK, calls X::f (qualified lookup) f(); // OK, calls B1::f (unqualified lookup) } }; // C++98 rules: B1::f hides X::f, so even though X::f can be reached from D // through B2, it is not found by name lookup from D. // C++11 rules: lookup set for f in D finds nothing, proceeds to bases // lookup set for f in B1 finds B1::f, and is completed // merge replaces the empty set, now lookup set for f in C has B1::f in B1 // lookup set for f in B2 finds nothing, proceeds to bases // lookup for f in X finds X::f // merge replaces the empty set, now lookup set for f in B2 has X::f in X // merge into C finds that every subobject (X) in the lookup set in B2 is a base // of every subobject (B1) already merged, so the B2 set is discarded // C is left with just B1::f found in B1 // (if struct D : B2, B1 was used, then the last merge would *replace* C's // so far merged X::f in X because every subobject already added to C (that is X) // would be a base of at least one subobject in the new set (B1), the end // result would be the same: lookup set in C holds just B1::f found in B1)
- Unqualified name lookup that finds static members of
B
, nested types ofB
, and enumerators declared inB
is unambiguous even if there are multiple non-virtual base subobjects of typeB
struct V { int v; }; struct B { int a; static int s; enum { e }; }; struct B1 : B, virtual V {}; struct B2 : B, virtual V {}; struct D : B1, B2 {}; void f(D& pd) { ++pd.v; // OK: only one v because only one virtual base subobject ++pd.s; // OK: only one static B::s, even though found in both B1 and B2 int i = pd.e; // OK: only one enumerator B::e, even though found in both B1 and B2 ++pd.a; // error, ambiguous: B::a in B1 and B::a in B2 }
Friend function definition
For a name used in a friend function definition inside the body of the class that is granting friendship, unqualified name lookup proceeds the same way as for a member function. For a name used in a friend
int i = 3; // found 3rd for f1, found 2nd for f2 struct X { static const int i = 2; // found 2nd for f1, never found for f2 friend void f1(int x) { // int i; // found 1st i = x; // finds and modifies X::i } friend int f2(); // static const int i = 2; // found 2nd for f1 anywhere in class scope }; void f2(int x) { // int i; // found 1st i = x; // finds and modifies ::i }
Friend function declaration
For a name used in the declarator of a friend function declaration that friends a member function from another class, if the name is not a part of any template argument in the declarator
template<class T> struct S; // the class whose member functions are friended struct A { typedef int AT; void f1(AT); void f2(float); template<class T> void f3(); void f4(S<AT>); }; // the class that is granting friendship for f1, f2 and f3 struct B { typedef char AT; typedef float BT; friend void A::f1(AT); // lookup for AT finds A::AT (AT found in A) friend void A::f2(BT); // lookup for BT finds B::BT (BT not found in A) friend void A::f3<AT>(); // lookup for AT finds B::AT (no lookup in A, because // AT is in the declarator identifier A::f3<AT>) }; // the class template that is granting friendship for f4 template<class AT> struct C { friend void A::f4(S<AT>); // lookup for AT finds A::AT // (AT is not in the declarator identifier A::f4) };
Default argument
For a name used in a default argument in a function declaration, or name used in the expression part of a member-initializer
class X { int a, b, i, j; public: const int& r; X(int i): r(a), // initializes X::r to refer to X::a b(i), // initializes X::b to the value of the parameter i i(i), // initializes X::i to the value of the parameter i j(this->i) // initializes X::j to the value of X::i {} }; int a; int f(int a, int b = a); // error: lookup for a finds the parameter a, not ::a // and parameters are not allowed as default arguments
Static data member definition
For a name used in the definition of a static data member, lookup proceeds the same way as for a name used in the definition of a member function.
struct X { static int x; static const int n = 1; // found 1st }; int n = 2; // found 2nd int X::x = n; // finds X::n, sets X::x to 1, not 2
Enumerator declaration
For a name used in the initializer part of the enumerator declaration
const int RED = 7; enum class color { RED, GREEN = RED + 2, // RED finds color::RED, not ::RED, so GREEN = 2 BLUE = ::RED + 4 // qualified lookup finds ::RED, BLUE = 11 };
Handler of a function try block
For a name used in the handler of a function try
int n = 3; // found 3rd int f(int n = 2) // found 2nd try { int n = -1; // never found } catch(...) { // int n = 1; // found 1st assert(n == 2); // loookup for n finds function parameter f throw; }
Overloaded operator
For an operator used in expression (e.g., operator+ used in a + b), the lookup rules are slightly different from the operator used in an explicit function-call expression such as operator+(a, b) : when parsing an expression, two separate lookups are performed: for the non-member operator overloads and for the member operator overloads (for the operators where both forms are permitted). Those sets are then merged with the built-in operator overloads on equal grounds as described in overload resolution
struct A {}; void operator+(A, A); // user-defined non-member operator+ struct B { void operator+(B); // user-defined member operator+ void f(); }; A a; void B::f() // definition of a member function of B { operator+(a, a); // error: regular name lookup from a member function // finds the declaration of operator+ in the scope of B // and stops there, never reaching the global scope a + a; // OK: member lookup finds B::operator+, non-member lookup // finds ::operator+(A, A), overload resolution selects ::operator+(A, A) }
Template definition
For a non-dependent name dependent name used in a template definition, the lookup is postponed until the template arguments are known, at which time ADL examines function declarations with external linkage (until C++11) that are visible from the template definition context as well as in the template instantiation context, while non-ADL lookup only examines function declarations with external linkage (until C++11)
void f(char); // first declaration of f template<class T> void g(T t) { f(1); // non-dependent name: lookup finds ::f(char) and binds it now f(T(1)); // dependent name: lookup postponed f(t); // dependent name: lookup postponed // dd++; // non-dependent name: lookup finds no declaration } enum E { e }; void f(E); // second declaration of f void f(int); // third declaration of f double dd; void h() { g(e); // instantiates g<E>, at which point // the second and the third uses of the name 'f' // are looked up and find ::f(char) (by lookup) and ::f(E) (by ADL) // then overload resolution chooses ::f(E). // This calls f(char), then f(E) twice g(32); // instantiates g<int>, at which point // the second and the third uses of the name 'f' // are looked up and find ::f(char) only // then overload resolution chooses ::f(char) // This calls f(char) three times } typedef double A; template<class T> class B { typedef int A; }; template<class T> struct X : B<T> { A a; // lookup for A finds ::A (double), not B<T>::A };
Note: see dependent name lookup rules for the reasoning and implications of this rule.
Template name
This section is incomplete Reason: dual-scope lookup of the template name after -> and . |
Member of a class template outside of template
This section is incomplete |
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 490 | C++98 | any name in a template argument in a friend member function declaration was not looked up in the scope of the member function's class |
only excludes the names in template arguments in the declarator identifier |
CWG 514 | C++98 | any unqualified name used in namespace scope was first looked up in that scope |
the unqualified names used to define a namespace variable member outside that namespace are first looked up in that namespace |
References
- C++23 standard (ISO/IEC 14882:2024):
- 6.5 Name lookup [basic.lookup] (p: 44-45)
- 6.5.2 Member name lookup [class.member.lookup] (p: 45-47)
- 13.8 Name resolution [temp.res] (p: 399-403)
- C++20 standard (ISO/IEC 14882:2020):
- 6.5 Name lookup [basic.lookup] (p: 38-50)
- 11.8 Member name lookup [class.member.lookup] (p: 283-285)
- 13.8 Name resolution [temp.res] (p: 385-400)
- C++17 standard (ISO/IEC 14882:2017):
- 6.4 Name lookup [basic.lookup] (p: 50-63)
- 13.2 Member name lookup [class.member.lookup] (p: 259-262)
- 17.6 Name resolution [temp.res] (p: 375-378)
- C++14 standard (ISO/IEC 14882:2014):
- 3.4 Name lookup [basic.lookup] (p: 42-56)
- 10.2 Member name lookup [class.member.lookup] (p: 233-236)
- 14.6 Name resolution [temp.res] (p: 346-359)
- C++11 standard (ISO/IEC 14882:2011):
- 3.4 Name lookup [basic.lookup]
- 10.2 Member name lookup [class.member.lookup]
- 14.6 Name resolution [temp.res]
- C++98 standard (ISO/IEC 14882:1998):
- 3.4 Name lookup [basic.lookup]
- 10.2 Member name lookup [class.member.lookup]
- 14.6 Name resolution [temp.res]