我试图从“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
,则甚至不允许编译器使用{{1}}。这是怎么回事?
答案 0 :(得分:4)
我认为你已经超过了“Koenig查询”(是的,同样的Koenig,所以你认为他已经发现了问题),又名“ADL”。
假设暂时通过间接包含,<algorithm>
已被拉入。
如果std::vector<int>::iterator
(参数的类型)是命名空间std
中的一个类,那么std::find
就是您的通话匹配,即使您从未“使用过”它,所以电话是模棱两可的。
如果std::vector<int>::iterator
为int*
,则std::find
不是候选人,并且通话不明确。
无论哪种方式都是std::vector
的有效实施,而且无论<iostream>
还是<vector>
是否包含<algorithm>
,它都是实施定义的。所以你的代码不可移植,但实现几乎无法诊断可移植性问题,除非代码实际上失败了。
在更典型的ADL案例中,关联命名空间中的函数或函数模板比调用者所居住或“使用”的命名空间中的函数或函数模板更好(更具体),因此避免了歧义。但是,您的全局find
基本上与std::find
相同,因此不适用。
#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
的名称可能意味着呼叫者需要小心。差异主要在于谁在错误发生时修复了错误。