name lookup
C++ has a principle that identifiers must be declared before they are used. When each identifier is used, its corresponding declaration must be found. This process is the name lookup.
The rules for name lookup vary in different structures of the program. It is briefly described below.
Unqualified name lookup
Simply put, it is a lookup of a single identifier.
Use of identifiers in namespaces
An identifier used in a namespace needs to be declared in the current or containing namespace before it can be used.
in a function defined in the namespace
This includes any symbols that appear after the function name, including types, default parameters, etc. appearing in the parameter list.
Its declaration needs to appear before it is used. Find the current block in turn, the block containing the current block, the namespace to which the function belongs, and the namespace's parent namespace.
namespace A {
namespace N {
void f();
}
}
void A::N::f() {
i = 5;
// i 的声明会在以下地方被查找:
// 1) A::N::f 中,i 的只用之前
// 2) namespace N
// 3) namespace A
// 4) 全局名字空间,A::N::f 的定义之前
}
the name in the class definition
A name in a class definition is looked up differently depending on whether it is in a complete-class context.
Complete-class context refers to: function body, function default parameters, noexcept-specifier, member initialization
Outside the complete-class context, before using the declaration, the search scope includes: the current class, the members of the base class, the class that contains the definition of the current class (if any) or its base class members, the function that contains the current class (if any) , contains the namespace of the current class.
namespace M {
class B { };
}
namespace N {
class Y : public M::B {
class X {
int a[i];
};
};
}
// 会在以下位置查找 i 的声明:
// 1) class N::Y::X 中,i 使用之前
// 2) class N::Y 中, N::Y::X 定义之前
// 3) N::Y’s 的基类 M::B
// 4) 名字空间 N, N::Y 定义之前
// 5) 全局名字空间, N 定义之前
In a complete-class context, when looking for class members, the member declaration is not required before the identifier is used, and the search scope includes: the current block or the containing block (if any), the current class member or the The members of the class defined by the class (if any) or its base class members, the functions that contain the current class (if any), the namespace that contains the current class.
class B { };
namespace M {
namespace N {
class X : public B {
void f();
};
}
}
void M::N::X::f() {
i = 16;
}
// 会在以下位置查找 i 的声明:
// 1) M::N::X::f, i 的使用之前
// 2) class M::N::X
// 3) M::N::X 的基类 B
// 4) namespace M::N
// 5) namespace M
// 6) global scope, M::N::X::f 定义之前
friend
If a friend function is defined in a class, its defined name lookup rules are the same as those of class members.
If the friend function is a class member, the identifier will be looked up first in the class in which the function is located, unless it is an identifier for template-argument in declarator-id .
struct A {
typedef int AT;
void f1(AT);
void f2(float);
template <class T> void f3();
};
struct B {
typedef char AT;
typedef float BT;
friend void A::f1(AT); // parameter type is A::AT
friend void A::f2(BT); // parameter type is B::BT
friend void A::f3<AT>(); // template argument is B::AT
};
Default parameters, mem-initializer
In the default parameters, expression of mem-initializer , function parameters are visible and override the outer declaration of the same name.
enumerate
In an enum definition, the defined enumerator is visible in subsequent definitions
static member
In the definition of a static member of a class, the name lookup rule is a member function of the same class
data members of the namespace
If the definition of a data member of a namespace occurs outside the namespace, the identifier lookup in its definition follows the same rules as when it was defined in its namespace.
namespace N {
int i = 4;
extern int j;
}
int i = 2;
int N::j = i; // N::j == 4
Argument-dependet name lookup
This rule is used for function calls.
typedef int f;
namespace N {
struct A {
friend void f(A &);
operator int();
void g(A a) {
int i = f(a); // f is the typedef, not the friend function: equivalent to int(a)
}
};
}
This lookup method is only used when the function is unqualified-id .
namespace N {
struct S { };
void f(S);
}
void g() {
N::S s;
f(s); // OK: calls N::f
(f)(s); // error: N::f not considered; parentheses prevent argument-dependent lookup
}
When the usual unqualified name lookup can be found
- a class member
- A block-level function declaration (remove using-declaration )
- When not a function or function template declaration
Argument-dependent name lookup does not take effect. Otherwise, the results of the lookup will contain the union of the ordinary lookup results and the Argument-dependent name lookup results.
Argument-dependent name lookup actually looks in the same namespace as the argument type, and:
- Ignore using-directive
- Declarations that are not functions and function templates are ignored
- Metafunctions defined in classes can be found
Qualified name lookup
In the form of A::B::C
, searches for B
and C
are all qualified name lookups.
Look in the global namespace starting with ::
.
If the part before ::
is an enumeration, it should be the enumerator in that enumeration.
...
type-name ::
~
type-name in (two type-name not necessarily the same), the second type-name the first type-name look in the same range .
When before ::
is not an enumeration, it may be a class, or a namespace.
class member
When it is a class before ::
, it is searched in class members and base classes. (Note that it is a base class, not a member of the base class.) But there are a few exceptions:
- lookup for destructors (see above)
- conversion-function-id in conversion-type-id lookup like member access
- template-id in template-argument in the context of the entire postfix-expression
- The name in using-declaraion , you can find the currently hidden class or enumeration
namespace member
A lookup for members of the namespace will start with the members of the namespace itself. Members introduced via using-directive will only be looked up if this lookup yields no results.
Elaborated type specifiers
Such as class A
, struct B::C
and so on.
For unqualifed-id, follow the unqualified name lookup rules, but ignore all non-type declarations.
For class
, struct
, union
a new class may be declared if not found.
If it is a qualified-id, use the Qualified name lookup rule, ignoring all non-type names. At this point, the new type is not declared even if it cannot be found.
Class member access
a.b
, p->c
If id-expression
is an unqualified-id, then do a lookup in the object class.
In the form a.B::b
, B
will be looked up in the class of a first. If not found, it will look in the context of the entire postfix-expression .
Look up the entire postfix-expression context for template-arguments in simple-template-id .
In conversion-function-id , its conversion-type-id in object class. If not found, look in the entire postfix-expression . Names other than types (or type templates) are ignored during all lookups.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。