如何避免由于Koenig查找引起的std命名冲突

时间:2017-10-03 19:24:27

标签: c++ stl namespaces std argument-dependent-lookup

作为一项学习练习,我一直reimplementing some of the STL algorithm。即使我没有添加任何using指令或使用std命名空间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(...)上进行了每次调用。是否有任何方法可以使用完全限定名称来避免与std名称的命名冲突?

4 个答案:

答案 0 :(得分:3)

  

我认为这是因为当我将std :: vector迭代器作为参数传递给我的函数时,参数依赖查找从std命名空间引入函数。

这是正确的。由于std::vector::iterator位于std,因此会在std中进行查找。

  

有没有办法使用完全限定名称来避免与std名称的命名冲突?

不幸的是没有。您需要符合要求来自全球空间的

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

答案 1 :(得分:2)

您可以按照以下方式消除呼叫歧义

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

如果没有这个,编译器是正确的,因为你已经注意到由于参数依赖的查找而导致调用不明确

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

  

我在表格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);