C++ 如何避免Koenig查找导致的std命名冲突

C++ 如何避免Koenig查找导致的std命名冲突,c++,stl,namespaces,std,argument-dependent-lookup,C++,Stl,Namespaces,Std,Argument Dependent Lookup,作为一项学习活动,我一直在努力。即使我没有为std名称空间添加任何using指令或using声明 我假设这是由于当我将std::vector迭代器作为参数传递给函数时,依赖于参数的查找从std名称空间引入函数 一个小程序来说明我的问题: #include <vector> #include <algorithm> namespace danstd { template <typename I, typename T> I find(I b, I e, T v

作为一项学习活动,我一直在努力。即使我没有为std名称空间添加任何using指令或using声明

我假设这是由于当我将
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;
}
#包括
#包括
名称空间danstd{
模板
我发现(I b,I e,T val){
对于(;b!=e;++b){
如果(*b==val)
返回b;
}
返回e;
}   
}
使用名称空间danstd;
int main(){
向量v={1,2,3};
自动i=查找(开始(v)、结束(v)、3);
返回i==结束(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,
     ^~~~
$g++-Wall foo.cpp
foo.cpp:在函数“int main()”中:
foo.cpp:16:37:错误:重载“find(std::vector::iterator,std::vector::iterator,int)”的调用不明确
返回*查找(开始(v),结束(v),3);
^
foo.cpp:5:3:注:候选者:我找到(I,I,T)[带I=\uu gnu\u cxx::\uu normal\u迭代器;T=int]
我发现(I b,I e,T val){
^~~~
在/usr/include/c++/6/algorithm:62:0中包含的文件中,
来自foo.cpp:2:
/usr/include/c++/6/bits/stl_algo.h:3784:5:注:候选:_iiterstd::find(_IIter,_IIter,const _Tp&)[带_IIter=u gnu_cxx::u normal_迭代器;_Tp=int]
查找(\u inputierator\uuu first,\u inputierator\uu last,
^~~~

在单元测试代码中,我已经链接到上面,我将我的函数包装在一个danstd名称空间中,每次调用的形式都是
danstd::function(…)
。有没有办法避免使用完全限定名来避免与std名称的命名冲突?

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

return *::find(begin(v), end(v), 3);
如果没有这一点,编译器是正确的,调用是不明确的,正如您所指出的,这是由于依赖于参数的查找

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

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

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

不幸的是,没有。你需要证明你想要的是来自全局空间的

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

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

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

我对表单
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);
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);

将您的实现放入您自己的命名空间中,并显式引用它,
yournamespace::find()
。毕竟,您必须已经获得了强烈推荐的编程实践,即显式引用
std::find()
,以调用适当的算法,并且您永远不会调用
find()
凭空,依靠Koenig查找..所以,这只是保持一致。相关:这不是问题所在,但
*查找(无论什么)
在找不到搜索目标时会给您带来问题。在这种情况下,
find
返回一个结束迭代器,它不需要是可取消引用的。@PeteBecker.Yup.刚刚写了一些快速的东西来演示编译错误。代码段已经编辑。“std::vector::iterator生活在std中”。不需要。顺便说一句,它可以是
int*
@DeiDei。这是一种很好的方法,可以从名称空间中使用名称,而不必限定它们,也不必使用using语句。@StoryTeller不太需要。我们不是说始终完全限定名称是最佳做法吗?除非有非常有用的情况,否则这只是OP的iss的原因ue.@DeiDei-那好吧。重载运算符或调用内联定义的友元函数也很有趣。@DeiDei在编写泛型代码时,这一点也非常重要。如果您有一个使用
+
的模板函数,并且该类型没有将其作为成员函数提供,但它与自由函数位于同一命名空间中,则它会找到它,然后工作