Cracking C++(4):头文件不能使用using namespace std吗?

文章目录

    • 1. 目的
    • 2. 显式声明
    • 3. 在头文件的函数定义里使用 using namespace xxx
    • 4. ADL:函数参数使用完整名字,调用函数时候可以不写 namespace
    • 5. 结论
    • 5. References

1. 目的

初学者容易直接写 using namespace std, 对于 hello world 的 demo 工程来说完全 OK, 但是容易带着这种习惯,在工程的 .h/.hpp 文件中也这样用。

于是, 会被一些“高手”告诫: 别在头文件里使用 using namespace, 否则将会引入大量潜在的命名冲突。

然而这个说法也不准确。

2. 显式声明

using namespace std

改为

using std::cin;
using std::cout;

优点: 只引入了需要的。
缺点: 需要多打几个字母。

3. 在头文件的函数定义里使用 using namespace xxx

关于能否在头文件中定义函数, 是另一个话题了, 简单的结论是: 对于模板函数,通常是放在头文件里; 如果打算做一个 header-only 的库, 主要目的也许是快速开发, 那也是ok的。于是可以像下面这样写:

template <typename FloatType> inline
FloatType compute_something(FloatType x)
{
    using namespace std; // No problem since scope is limited
    return exp(x) * (sin(x) - cos(x * 2) + sin(x * 3) - cos(x * 4));
}

优点: std 只影响当前函数, 换言之范围被限定了, 不会传播到包含当前头文件的文件中的全局范围。

4. ADL:函数参数使用完整名字,调用函数时候可以不写 namespace

这算是一个相关话题了。

ADL 是 Argument-dependent name lookup 的缩写,看个例子就明白了:

namespace NS {

class A {};

void f(A& a, int i) {}

}  // namespace NS

int main() {
   NS::A a;
   f(a, 0);  // Calls NS::f.
}

由于参数 a 在定义时是 NS::A 类型, 因此在调用 f(a, 0) 时, 参数 a 所属的命名空间 NS 被作为候选命名空间的一个元素,用于查找 f 函数。 进而匹配到了 NS::f.

5. 结论

在 C++ 的头文件中, 如果是全局作用域里, 请不要使用 using namespace std.

但在 C++ 的头文件中, 在一个函数内部, 甚至一个 namespace 内部, 可以使用 using namespace std.

以上结论适合替换为 using namespace 你的ns, 以及 using std::cout 等形式的单个引入。

5. References

  • https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice
  • https://en.wikipedia.org/wiki/Argument-dependent_name_lookup

你可能感兴趣的:(C/C++,c++,开发语言)