根据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和指定的命名空间。”
重要的是要记住这一点
声明的封闭名称空间是声明词汇出现的名称空间,除了在其原始名称空间之外重新声明名称空间成员(例如,[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::hello
与NS1::NS2::hello
相关联并解决它的定义。
在OP的全局命名空间中,otherHello
之前没有任何东西。因此,不会发生名称查找。它正如我之前引用的那样立即在封闭命名空间中定义该函数。