为什么using指令不是"关联"具有普通功能?

时间:2017-07-09 08:29:57

标签: c++ namespaces

根据this question,在using指令之后定义类方法是有效的,而不是将它们包含在namespace块中。

然而,普通功能似乎并非如此。考虑:

Greeting.hh

#pragma once

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

    void otherHello();
}

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;
}

main.cc

#include "Greeting.hh"

int main()
{
    NS::Greeting o;
    o.hello();
    NS::otherHello();
}

这不会编译,产生以下错误消息:

undefined reference to `NS::otherHello()'

进一步检查表明otherHello的符号前面没有命名空间,而Greeting::hello&#39; s是:

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

这是否与accepted answer的标准参考相矛盾?

  

&#34;在非限定名称查找(3.4.1)期间,名称显示为好像   在包含两者的最近的封闭命名空间中声明   using-directive和指定的命名空间。&#34;

1 个答案:

答案 0 :(得分:6)

重要的是要记住

  1. 不同命名空间中的函数声明不会相互干扰。
  2. 函数的定义也是声明。
  3. [namespace.def/4]
  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;
    }
    

    当编译器遇到NS2::hello被定义时,它会预先为该声明符id进行名称查找。根据{{​​3}}:

      

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

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

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