为什么 using 指令不能与普通函数"associate"?

Why does the using directive not "associate" with ordinary functions?

本文关键字:函数 associate using 指令 不能 为什么      更新时间:2023-10-16

根据这个问题,在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()

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

"在非限定名称查找 (3.4.1( 期间,名称看起来好像它们 在最近的封闭命名空间中声明,该命名空间包含两者 使用指令和指定的命名空间。

重要的是要记住

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

声明的封闭命名空间是 声明在词法上出现,除了重新声明 其原始命名空间之外的命名空间成员(例如,定义 如 [命名空间.memdef] 中指定(。这样的重新声明具有相同的 将命名空间作为原始声明括起来。

因此,让我们看一下otherHello定义。它在词汇上出现在哪里?当然是在全局命名空间中。这也是它的宣言要点。这意味着封闭的命名空间是全局命名空间,您最终会得到::otherHello的声明。

所以不,这与另一个问题的公认答案中的标准引用并不矛盾。成员函数可以在类外部定义,只要它们由其类名 ([class.mfct/4]( 限定

如果成员函数的定义在词法上超出其类 定义,成员函数名称应由其类限定 使用 :: 运算符命名。

所以我们只需要问,Greeting命名的类和NS::Greeting相同吗?为什么,是的。use 指令对此负责。


我将添加此部分,希望澄清。请考虑以下代码片段:

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]:

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

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

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