命名空间
变体
操作

限定名称查找

来自 cppreference.com
< cpp‎ | language
 
 
C++ 语言
表达式
替代表示
字面量
布尔值 - 整数 - 浮点数
字符 - 字符串 - nullptr (C++11)
用户定义的 (C++11)
实用程序
属性 (C++11)
类型
typedef 声明
类型别名声明 (C++11)
强制转换
内存分配
类特定的函数属性
explicit (C++11)
static

特殊成员函数
模板
其他
 
 

限定名称是在作用域解析运算符 :: 右侧出现的名称(另请参阅 限定标识符)。限定名称可以指代

  • 类成员(包括静态和非静态函数、类型、模板等),
  • 命名空间成员(包括另一个命名空间),
  • 枚举器。

如果 :: 左侧没有内容,则查找只考虑 全局命名空间范围 中的声明。这使得即使名称被局部声明隐藏,也可以引用这些名称

#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 起)

[编辑] 类成员

如果左侧名称的查找结果是类/结构或联合名称,则在该类的作用域中查找 :: 右侧的名称(因此可以找到该类或其基类的成员声明),以下情况除外

  • 析构函数的查找方式如上所述(在 :: 左侧名称的作用域中)。
  • 用户定义的转换 函数名称中的转换类型标识符首先在类的作用域中查找。如果未找到,则在当前作用域中查找该名称。
  • 模板参数中使用的名称在当前作用域中查找(而不是在模板名称的作用域中)。
  • 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 中找到的所有由 using-directives 命名的命名空间以及在 N 的所有传递性内联命名空间成员中的所有声明。这些规则会递归应用

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
}

[编辑] 缺陷报告

以下改变行为的缺陷报告被追溯应用到之前发布的 C++ 标准。

DR 应用于 已发布的行为 正确行为
CWG 215 C++98 :: 前面的名称必须是类名或命名空间
名称,因此模板参数不允许在那里使用
该名称必须指定一个类,
命名空间或依赖类型
CWG 318 C++98 如果 :: 右侧的名称与左侧的名称相同
作为左侧的名称,限定名总是
被认为命名了该类的构造函数
只命名构造函数
当可接受时(例如,不在
详细的类型说明符中)

[编辑] 另请参阅