1

我正在尝试运行“Accelerated 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。这里发生了什么?

4

1 回答 1

4

我认为你已经绊倒了“Koenig 查找”(是的,同一个 Koenig,所以你会认为他会发现问题),也就是“ADL”。

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

如果std::vector<int>::iterator(参数的类型)是 namespace 中的一个类std,那么std::find即使您从未“使用”它,它也与您的调用匹配,因此该调用是模棱两可的。

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

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

在更典型的 ADL 案例中,关联命名空间中的函数或函数模板比​​调用者居住或“使用”的命名空间中的函数或函数模板更好(更具体),因此避免了歧义。但是您的 globalfind与 基本相同std::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 template\n";
    }
    /* this would be a better match
    void func(Foo) {
        std::cout << "namespace function\n";
    }
    */
}

template <typename T>
void func(T) {
    std::cout << "global function template\n";
}

int main() {
    foo::Foo f;
    func(f);
}

结果:

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

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

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

于 2012-05-31T00:05:59.463 回答