【问题标题】:Strange overloading rules in C++C++ 中奇怪的重载规则
【发布时间】:2010-05-28 06:49:56
【问题描述】:

我正在尝试使用 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(但我不太确定)。

所以 GCC 可能使用 iterator_b 之类的东西,而 Comeau 使用 iterator_a

【问题讨论】:

  • 我觉得 Comeau 的行为很奇怪,这意味着他们的 iterator 不在 std 命名空间中,还是我遗漏了什么?
  • 我用一些你可以玩的代码更新了答案。

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


【解决方案1】:

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

模棱两可的过载是由于argument dependent lookup。 C++ 标准没有指定应该如何实现std::vector&lt;*&gt;::iterator。 gcc 库编写者选择使用模板类型参数为 std::vector 的模板 (__gnu_cxx::__normal_iterator),这会将命名空间 std 带入关联命名空间列表中。


这是有效的 C++ 吗?

是的,但两个编译器的行为也符合 C++ 标准。从这个角度来看,ADL 非常令人头疼,直到标准化之后才了解其全部后果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-12
    • 1970-01-01
    • 1970-01-01
    • 2017-09-05
    • 1970-01-01
    • 2011-10-31
    • 2016-02-03
    相关资源
    最近更新 更多