C++中的命名空间冲突

8
我不明白为什么这段代码无法编译:

namespace A {
        class F {};             // line 2
        class H : public F {};
}

namespace B {
        void F(A::H x);         // line 7
        void G(A::H x) {
                F(x);           // line 9
        }
}

我正在使用 gcc 4.3.3,出现的错误是:

s3.cpp: In function ‘void B::G(A::H)’:
s3.cpp:2: error: ‘class A::F’ is not a function,
s3.cpp:7: error:   conflict with ‘void B::F(A::H)’
s3.cpp:9: error:   in call to ‘F’

我认为由于第9行中没有命名空间前缀,F(x) 应该明确表示只有 B::F(x)。编译器尝试将 x 转换为其自身的超类。在我的理解中,它不应该这样做。为什么会这样呢?

4个回答

12
那是因为编译器会在相同命名空间中搜索其参数的函数。编译器找到了A::F标识符,但它不是一个函数。结果会导致错误。
据我所知,这是标准行为。
引用块: 3.4.2 参数相关的名称查找 当未限定的名称用作函数调用中的后缀表达式时(5.2.2),除了通常的未限定查找(3.4.1)之外,可能会搜索其他命名空间,并且可能会找到在命名空间范围内的友元函数声明(11.4)。这些对搜索的修改取决于参数的类型(对于模板模板参数,还取决于模板参数的命名空间)。
对于函数调用中的每个参数类型T,都存在一组零个或多个关联的命名空间和一组零个或多个关联的类需要考虑。命名空间和类的集合完全由函数参数的类型(以及任何模板模板参数的命名空间)确定。 用于指定类型的typedef名称和using声明不会为此集合做出贡献。命名空间和类的集合的确定方式如下...
这条规则允许您编写以下代码:
std::vector<int> x;
// adding some data to x
//...

// now sort it
sort( x.begin(), x.end() ); // no need to write std::sort

最后:由于核心问题218,一些编译器可以在不出现任何错误的情况下编译所涉及的代码。


1
所谓的Koenig查找实际上在C++标准的3.4.2节中有所描述。 - anon
那么,如果 Visual Studio 编译通过,这是一个 bug 吗? - liori
你能找到那个声明的参考资料吗?我从未听说过任何类似的规定... - xtofl
@liori,Visual Studio编译此代码是因为Core Issue 218。 - Kirill V. Lyadvinsky

5

这是我自己的代码的最小示例,可以在我朋友的VS2005上编译。虽然我没有测试过这个确切的部分。而且...DeusAduro似乎没有问题在VS2005上编译它。 - liori
这个错误报告看起来很像,尽管它涉及到模板,而模板有一个不同的(两阶段)查找方案。 - xtofl
注意:其他人报告VS2005可以按预期编译此代码。我尝试了Comeau的Test Drive -> 成功。似乎只有gcc遇到了这个问题。 - xtofl
如果jia3ep的答案是正确的,我相信它是正确的,那么gcc并没有“受苦”,但通常情况下,VS是不符合标准的。 - rmeador
@xtofl:至少我提到的第一个漏洞在这里可以找到:http://gcc.gnu.org/bugzilla/show_bug.cgi?id=25980,而且已经被标记为与此漏洞重复。 - schnaader
@rmeador,看起来VS在最新版本中完全符合要求。 - Kirill V. Lyadvinsky

1
非常奇怪,我直接复制粘贴到VS 2005中,结果出现了一个错误,这是我预料中的:
错误1:错误LNK2001:未解析的外部符号“void __cdecl B :: F(class A :: H)”
因为我们实际上还没有在命名空间B中定义F(x)……不确定为什么Gcc会出现这个错误。

0

我刚刚尝试在Visual Studio 2005上编译它,结果很好。我想知道这是否是参数相关查找的错误实现,其中参数的命名空间被意外地引入了进来?


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