为什么using指令不与普通函数"关联"?

Grz*_*ski 10 c++ namespaces

根据这个问题,在using指令之后定义类方法是有效的,而不是将它们包含在namespace块中.

但是,普通功能似乎并非如此.考虑:

Greeting.hh

#pragma once

namespace NS
{
    class Greeting
    {
    public:
        void hello();
    };

    void otherHello();
}
Run Code Online (Sandbox Code Playgroud)

Greeting.cc

#include "Greeting.hh"
#include <iostream>

using namespace NS;

void Greeting::hello()
{
    std::cout << "Greeting::hello" << std::endl;
}

void otherHello()
{
    std::cout << "otherHello" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

main.cc

#include "Greeting.hh"

int main()
{
    NS::Greeting o;
    o.hello();
    NS::otherHello();
}
Run Code Online (Sandbox Code Playgroud)

这将无法编译,产生以下错误消息:

undefined reference to `NS::otherHello()'
Run Code Online (Sandbox Code Playgroud)

进一步检查表明,otherHello符号前面没有命名空间,而Greeting::hellos是:

g++ -std=c++14 -pedantic -Wall -c Greeting.cc
nm -C Greeting.o | grep T
000000000000002a T otherHello()
0000000000000000 T NS::Greeting::hello()
Run Code Online (Sandbox Code Playgroud)

这与接受的答案中的标准参考是否相矛盾?

"在非限定名称查找(3.4.1)期间,名称看起来好像是在最近的封闭命名空间中声明的,其中包含using-directive和指定的命名空间."

Sto*_*ica 6

重要的是要记住这一点

  1. 不同命名空间中的函数声明不会相互干扰.
  2. 函数的定义也是一个声明.
  3. [namespace.def/4]

声明的封闭名称空间是声明词汇表中出现的名称空间,除了在其原始名称空间之外重新声明名称空间成员(例如,[namespace.memdef]中指定的定义).这样的重新声明具有与原始声明相同的封闭名称空间.

那么让我们来看看otherHello定义.词汇在哪里出现?当然,在全局命名空间中.这也是宣言的重点.这意味着封闭的命名空间是全局的,你最终会得到声明::otherHello.

所以不,这与另一个问题的接受答案的标准引用并不矛盾.成员函数可以在类之外定义,只要它们通过类名([class.mfct/4])限定:

如果成员函数的定义在词法定义之外是词法定义,则成员函数名称应使用::运算符通过其类名限定.

所以我们只需要问,Greeting同名的同名NS::Greeting吗?为什么,是的.using指令负责这一点.


我将添加这一部分,以期澄清.请考虑以下代码段:

namespace NS1 {
    namespace NS2 {
        void hello();
    }
}

using namespace NS1;

void NS2::hello() {

}

int main() {
    NS1::NS2::hello();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当编译器遇到NS2::hello被定义时,它会预先为该声明符id进行名称查找.根据[basic.lookup.qual/3]:

在declarator-id是qualified-id的声明中,在声明的qualified-id 之前使用的名称在定义的命名空间范围中被查找 ; 在成员的类或命名空间的范围内查找qualified-id后面的名称.

因此NS2,在定义范围(全局范围)中查找,并根据您引用的非限定名称查找规则,找到并解析为NS1::NS2.这NS2::hello就是NS1::NS2::hello定义它的方式和解决方法.

在OP的全局命名空间中,otherHello前面没有任何内容.因此,不会发生名称查找.它正如我之前引用的那样立即在封闭命名空间中定义该函数.