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

问题描述 投票:10回答:1

根据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的符号是:

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的标准参考文件相矛盾?

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

c++ namespaces
1个回答
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;
}

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

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.