C ++中的奇怪重载规则

时间:2010-05-28 06:49:57

标签: c++ templates namespaces g++ overloading

我正在尝试使用GCC 4.5.0编译此代码:

#include <algorithm>
#include <vector>

template <typename T> void sort(T, T) {}

int main()
{
    std::vector<int> v;
    sort(v.begin(), v.end());
}

但它似乎不起作用:

$ g++ -c nm.cpp
nm.cpp: In function ‘int main()’:
nm.cpp:9:28: error: call of overloaded ‘sort(std::vector<int>::iterator, std::vector<int>::iterator)’ is ambiguous
nm.cpp:4:28: note: candidates are: void sort(T, T) [with T = __gnu_cxx::__normal_iterator<int*, std::vector<int> >]
/usr/lib/gcc/i686-pc-linux-gnu/4.5.0/../../../../include/c++/4.5.0/bits/stl_algo.h:5199:69: note:                 void std::sort(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<int*, std::vector<int> >]

Comeau编译此代码时没有错误。 (4.3.10.1 Beta2,严格的C ++ 03,没有C ++ 0x)

这是有效的C ++吗?

为什么GCC甚至将std::sort视为有效过载?


我做了一些实验,我想我知道为什么Comeau 可以编译这个(但我不知道这个事实):

namespace foo {
typedef int* iterator_a;
class        iterator_b {};
template <typename T> void bar(T) {}
}

template <typename T> void bar(T) {}

int main()
{
    bar(foo::iterator_a()); // this compiles
    bar(foo::iterator_b()); // this doesn't
}

我的猜测是,第一个调用解析为bar(int*),因此没有ADL且没有歧义,而第二个调用解析为bar(foo::iterator_b)并拉入foo::bar(但我不是真的很确定。)

因此,当Comeau使用iterator_b时,GCC可能会使用类似iterator_a的内容。

1 个答案:

答案 0 :(得分:8)

您可以通过将名称完全限定为sort来明确指定::sort功能。

模糊的重载是argument dependent lookup引起的。 C ++标准没有规定应该如何实现std::vector<*>::iterator。 gcc库编写者已选择使用模板类型参数为__gnu_cxx::__normal_iterator的模板(std::vector),这会将名称空间std放入关联的名称空间列表中。


这是有效的C ++吗?

是的,但两个编译器的行为也符合C ++标准。从这个角度来看,ADL引起了巨大的麻烦,直到标准化之后才能理解其全部后果。