为什么编译器在这里抱怨函数歧义

Why does the compiler complain about function ambiguity here?

本文关键字:函数 歧义 编译器 在这里 为什么      更新时间:2023-10-16

我正在尝试运行"加速C++"(A. Koenig, B. Moo)(§8.2.2)一书中的一些示例代码:

#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::vector;
template <class In, class X>
In find(In begin, In end, const X &x)
{
    while (begin != end && *begin != x) {
        ++begin;
    }
    return begin;
}
int main()
{
    vector<int> v;
    v.push_back(5);
    v.push_back(32);
    v.push_back(42);
    v.push_back(7);
    cout << *find(v.begin(), v.end(), 42) << endl;
    return 0;
}

find函数在书中是这样的;我自己写的main函数。

clang++ 和 g++ 都不会编译它。似乎他们在抱怨我的find功能引入了std::find的歧义。但是,我从未在代码中使用过using namespace::std;using std::find;,因此如果包含编译器,甚至不应该允许编译器使用std::find。这是怎么回事?

我想你已经绊倒了"Koenig查找"(是的,同一个Koenig,所以你会认为他会发现问题),又名"ADL"。

假设通过间接包含,<algorithm>已被拉入。

如果std::vector<int>::iterator(参数的类型)是命名空间 std 中的一个类,则std::find是调用的匹配项,即使您从未"使用"过它,因此调用是不明确的。

如果std::vector<int>::iteratorint*,则std::find不是候选者,并且调用不是模棱两可的。

无论哪种方式都是std::vector的有效实现,并且无论<iostream><vector>是否包含<algorithm>,它都是实现定义的。因此,您的代码不可移植,但实现几乎无法诊断可移植性问题,除非代码在该实现上实际失败。

在更典型的 ADL 情况下,关联命名空间中的函数或函数模板比调用方驻留或"使用"的命名空间中的函数或函数模板更好(更具体),因此避免了歧义。但是您的全局findstd::find基本相同,因此不适用。

http://ideone.com/Cskur:

#include <iostream>
namespace foo {
    struct Foo {};
    /* same as the one we'll define later */
    template <typename T>
    void func(T) {
        std::cout << "namespace function templaten";
    }
    /* this would be a better match
    void func(Foo) {
        std::cout << "namespace functionn";
    }
    */
}
template <typename T>
void func(T) {
    std::cout << "global function templaten";
}
int main() {
    foo::Foo f;
    func(f);
}

结果:

prog.cpp:19: error: call of overloaded ‘func(foo::Foo&)’ is ambiguous

结论:使用来自std的名称有些危险,即使在其他命名空间中也是如此。

或者,如果您愿意:从其他命名空间中的std定义名称可能意味着调用方需要小心。区别主要在于谁在错误发生时修复错误。