使用命名空间避免名称冲突

3
我正在编译我工作的一个项目,这次使用的是VS2010,结果发现windows.h中的一个包含typedef INPUT的内容与我已有的代码中导出的常量字符串产生了冲突。//winuser.h(第5332行)
typedef struct tagINPUT {
    DWORD   type;

    union
    {
        MOUSEINPUT      mi;
        KEYBDINPUT      ki;
        HARDWAREINPUT   hi;
    };
} INPUT, *PINPUT, FAR* LPINPUT;

//foo.h

//stuff here
extern FOO_DLL_API const string INPUT;

现在,在有问题的 .cpp 文件中,我不使用 INPUT(而且我不拥有大部分代码),并试图最小化影响,我进行了以下操作:
//myfile.cpp
#include <foo.h>
namespace windowsLib {    //I added this
#  include <windows.h>
}

using namespace windowsLib;

到目前为止,这种方法运作良好,但我想问一下您是否认为这种方法存在潜在问题,或者您有更好的建议。
编辑:
感谢所有评论和解释,让我知道这是一个坏主意的原因。从您的评论中得出的结论是,我应该更改foo.h并将其内容放入命名空间中。然而,这样做会影响到数十个文件,甚至更多的文件,现在需要使用命名空间限定符。
有没有一种方法可以在不触及所有那些文件的情况下“正确地”做到这一点?
如果我是代码的所有者,我会进行此更改并完成它,但我必须提出一个解决方案并获得批准并指派给某人等等。因此,如果更改最小,则更容易。
编辑2:
我的最终提案是将类拆分为两部分,如下所示:
//stub.cpp
#include <windows.h>

//Implementation of wrapper methods

//stub.h

class stub {
    //public wrapper methods
}

//myfile.cpp

#include <stub.h>
#include <foo.h>    

我接受Benlitz的答案,因为那个建议也可以解决我当前面临的最小影响限制问题。不过,我还是感谢大家的意见。

4个回答

3

不仅语言本身不允许这样做(假设标准头文件将被包含在命名空间内),而且还会出现调用<windows.h>中声明的任何函数,而链接器将在windowsLib命名空间中查找它们的问题。

根本不起作用!


2
这似乎至少是个不好的想法。
1)如果那确实是你的代码,添加命名空间没有任何好处,因为下一行已经有了“using namespace windowsLib;”。无论如何,“INPUT”都会产生歧义吗?
2)你可能会包含其他使用“windows.h”中内容的头文件,并且不会使用正确的符号。想象一下,包含一个定义返回“INPUT”的函数的头文件。那该怎么办呢?
我建议你保险起见,只需重命名你的类型即可。

是的,输入(INPUT)仍然不明确,但是这个类别特别没有使用它。但是可以肯定的是,将来可能会使用它。这个“INPUT”常量在很多地方都被使用(直到最近才开始使用windows.h),所以更改它将是一件痛苦的事情(对我来说不是,因为我不维护那段代码,但是无论如何都是一件痛苦的事情),所以我更愿意向他们提出一个影响有限或能够防止未来问题的解决方案。 - JACH
裸的 INPUT 现在是不明确的(只要在使用时进行消歧义,可以作为 ::INPUTwindowsLib::INPUT),而不是具有两个不同定义的符号(非法)。 话虽如此,这样做不好。 我建议采用 @Benlitz 的方法。 - cvoinescu
@cvoinescu 我不建议那种方法。最好的方法是给变量重命名。那样只是预处理器的滥用。 - Luchian Grigore
当然,我的错。我误读了他的问题 - 我以为他说另一个标题是他无法控制的代码。 - cvoinescu

1

像其他答案所解释的那样,这是一个不好的想法。这里有一个可能会帮助您解决问题的想法:

//myfile.cpp

#define INPUT UnusedSymbol
#include "foo.h"
#undef INPUT

#include "windows.h"

这可能有效,因为INPUT是foo.h中的外部变量,只要您不在myfile.cpp中使用它,编译器和链接器都不会关心它。UnusedSymbol是一个虚拟名称,您可以使用任何在源代码中未使用过的名称。

我测试了这个解决方案,它有效。正如其他人指出的那样,也许我应该在foo.h中推动修复,但这是一个聪明的解决方案。 - JACH
好的,是的,这个答案是针对“最小化影响”的请求。我还建议您将foo.h放入命名空间中(当然,通过修改foo.h本身,而不是在#include周围编写命名空间声明)。 - Benlitz

1
将namespace放在windows.h周围对我来说听起来很危险。这可能会隐藏你需要的东西。除非你在下一行导入命名空间。
我宁愿将命名空间放在foo.h周围:
namespace fooLib {
#include "foo.h"
}

using fooLib;

我猜这只是将问题从操作系统代码转移到了foo代码,但对我来说似乎更安全。

另一种方法可能是在foo周围构建一个包装器,调用foo函数并在一个单独的小包装库中返回foo全局变量。其中一个不需要windows.h。您可以将此包装器放在命名空间中,以防止再次发生这种情况。

我假设您不能foo.h中重命名东西或将fooLib命名空间放在foo.h内部的东西周围。

如果您可以触摸foo.h,最好将foo.h中的INPUT重命名或将foo.h的内容放在自己的命名空间中。我认为fooLib命名空间会有很大(显而易见的)好处。


1
我在研究我的旧问题。你关于在foo周围构建包装器的评论接近我最终向代码所有者提出的建议。由于使用foo会很麻烦,我将windows.h依赖性封装在一个单独的文件中,并提供了一个包装器类。 - JACH

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