在C++中,我能否撤销“using namespace”的效果?

34

使用using namespace可以使整个命名空间的内容直接可见,无需使用命名空间限定符。如果在广泛使用的头文件中出现using namespace可能会导致问题 - 我们可能会意外地使两个具有相同类名称的命名空间可见,编译器将拒绝编译除非在类名称前加上命名空间限定符。

我能否撤销using namespace,使编译器忘记之前看到过它吗?


我敢打赌,使用预处理器一定有一个非常丑陋的黑科技可以解决这个问题。但我猜你不想要那个。 - Eli Bendersky
6
@Eli: Boost 库中没有相应的内容,这很可能意味着不存在。 - Travis Gockel
一个可能的解决方案,至少可以缩短你需要输入的内容,就是在文件顶部使用 #define N namespace::,并在底部使用 #undef N。当然,这意味着你必须小心,不要在文件中任何不想要 namespace:: 的地方使用 N。使用 typedef 也可能会有用。 - Yay295
7个回答

42

不可以。但你可以告诉你的同事,在头文件中,不应该使用using指令或声明。


4
很不幸,一个第三方库(https://opencv.org/platforms/cuda.html)需要这样做,我们无法重写它。这并不是一个解答,生活中有很多事情应该避免,但却是不可避免的。 - Audrius Meškauskas
@AudriusMeškauskas 不切实际并不意味着它是错误的。 - Mark Ransom

16

就像其他人说的那样,你是不能这样做的,而且这个问题在第一次出现时就不应该存在。
下一步最好的解决方法是引入所需的符号,使其被名称查找优先使用:

namespace A { class C {}; }
namespace B { class C {}; }
using namespace A;
using namespace B;

namespace D {
    using A::C; // fixes ambiguity
    C c;
}

在某些情况下,您还可以将有问题的包含文件放入命名空间中:

namespace offender {
#  include "offender.h"
}

7
最后一项技术可能会带来一些问题。如果offender.h文件包含了被#define保护的头文件,那么这些符号就会被卡在offender中。你可以尝试将其整个接口打包放在新的命名空间中,但仍需确保其中不包含系统头文件。而且,即使这一次能够正常运行,下一个版本也可能会出现问题。 - Potatoswatter

7
不,C++标准对“撤销”没有任何规定。你能做的最好的事情就是限制using的作用域:
#include <vector>

namespace Ximpl {

using namespace std;    
vector<int> x;

}

vector<int> z; // error. should be std::vector<int>

但不幸的是,using namespace Ximpl 也会引入 std 命名空间中的所有名称。


3
据我所知,没有这样的规定...但通常我只在.cpp文件中使用“using namespace”。

0

正如所述,您不应在头文件中使用using namespace sth。当您需要从命名空间中获取功能时,可以像这样利用作用域:

void func() {
    // some code agnostic to your namespace.
    {
        using namespace sth;
        // some code aware of sth.
    }
    // some other code agnostic to your namespace.
}

0

我尝试在头文件中使用的最接近的是以下内容:

//example.h

#ifndef EXAMPLE_H_
#define EXAMPLE_H_


/**
 * hating c++ for not having "undo" of using namespace xx
 */
#define string std::string
#define map std::map

class Example {
public:
    Example (const char *filename);
    Example (string filename);
    ~Example ();
private:
    map<string,complicated_stuff*> my_complicated_map;

};

#undef string
#undef map

#endif //EXAMPLE_H_

毕竟,定义可以被取消。 有两个问题: 1. 它很丑陋 2. 分别使用 #define 和 #undef 为每个名称从相应的命名空间中使用


0
  1. 这个线程已经有点老了,尽管 @rlbond 可能已经将“命名空间声明”与“使用指令”分开了,所以我必须在这里考虑一下。
  2. @Georg Fritzsche 通过给他的“罪犯”命名来鼓励有毒的环境。至少,你发现任何工作产品都是商业上不可接受的。
  3. 就个人而言,我不喜欢到处洒“std::”(它会变成一群蚊子),但我同意 @rlbond 的观点,避免在任何头文件中使用任何 using namespace 子句。将执行代码与头文件分离(例如:建立链接库)始终是良好的编程实践。

不要使用 using namespace std,而是有选择地使用 using std::vector; using std::string;,这样你就会少遇到很多麻烦。 - Mark Ransom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接