如何避免因 Koenig 查找而导致的标准命名冲突

How avoid std naming conflicts due to Koenig lookup

作为学习练习,我已经 reimplementing some of the STL algorithm. Even though I've not added any using directives or using declarations for the std namespace my test code won't compile unless I explicitly prefix those functions shadowing std names

我假设这是由于参数依赖查找在我将 std::vector 迭代器作为参数传递给我的函数时从 std 命名空间引入了函数。

一个小程序来说明我的问题:

#include <vector>
#include <algorithm>

namespace danstd {
template <typename I, typename T>
I find(I b, I e, T val) {
    for (; b != e; ++b) {
        if (*b == val)
            return b;
    }
    return e;
}   
}

using namespace danstd;

int main() {
    std::vector<int> v = {1, 2, 3};

    auto i = find(begin(v), end(v), 3);
    return i == end(v) ? -1 : *i;
}

编译时,我看到这些错误消息:

$ g++ -Wall foo.cpp
foo.cpp: In function ‘int main()’:
foo.cpp:16:37: error: call of overloaded ‘find(std::vector<int>::iterator, std::vector<int>::iterator, int)’ is ambiguous
     return *find(begin(v), end(v), 3);
                                     ^
foo.cpp:5:3: note: candidate: I find(I, I, T) [with I = __gnu_cxx::__normal_iterator<int*, std::vector<int> >; T = int]
 I find(I b, I e, T val) {
   ^~~~
In file included from /usr/include/c++/6/algorithm:62:0,
                 from foo.cpp:2:
/usr/include/c++/6/bits/stl_algo.h:3784:5: note: candidate: _IIter std::find(_IIter, _IIter, const _Tp&)[with _IIter = __gnu_cxx::__normal_iterator<int*, std::vector<int> >; _Tp = int]
     find(_InputIterator __first, _InputIterator __last,
     ^~~~

在我链接到上面的单元测试代码中,我将我的函数包装在一个 danstd 命名空间中,并且我在表单 danstd::function(...) 上进行每次调用。有什么办法可以避免使用完全限定名称来避免与标准名称的命名冲突?

您可以按如下方式消除调用歧义

return *::find(begin(v), end(v), 3);

否则,编译器是正确的,正如您所注意到的,由于参数依赖查找,调用是不明确的

I assume that this is due to argument dependent lookup bringing in functions from the std namespace when I pass std::vector iterators as parameters to my functions.

没错。由于 std::vector::iterator 居住在 std 中,它将在 std 中进行查找。

Is there any way around having to use fully qualified names to avoid the naming conflicts with std names?

很遗憾没有。您需要符合您想要来自全球 space like

的条件
return *::find(begin(v), end(v), 3);

C++ 旨在将函数与给定命名空间中的类型相关联。只要使用名称空间来封装库,这就是一个有效的假设。

您的算法库的类型是在另一个已经定义了相同算法的库的命名空间中定义的。一种解决方案是实现您自己的类型……即使是一个标准容器也是一种练习 ;) .

I make each call on the form danstd::function(...).

不,你不是。你有一个 using namespace danstd 语句将你的 find() 函数转储到全局命名空间中,然后你在没有限定它的情况下调用它。

因此,要么从全局命名空间中限定它:

namespace danstd {
    ...
    template <typename I, typename T>
    I find(I b, I e, const T &val) { ... }
}

using namespace danstd;

auto i = ::find(begin(v), end(v), 3);

否则删除 using 语句并使用您的命名空间完全限定函数调用:

namespace danstd {
    ...
    template <typename I, typename T>
    I find(I b, I e, const T &val) { ... }
}

// using namespace danstd;

auto i = danstd::find(begin(v), end(v), 3);