I am trying to run some sample code from the book “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;
}
The find function appears like this in the book; the main function I wrote myself.
Both clang++ and g++ won’t compile this. It seems as if they are complaining that my find function introduced an ambiguity with std::find. However, I never used using namespace::std; nor using std::find; in the code, so the compiler shouldn’t even be allowed to use std::find if it was included. What’s going on here?
I think you’ve tripped over “Koenig lookup” (yes, the same Koenig, so you’d think he’d spot the problem), aka “ADL”.
Suppose for a moment that via an indirect include,
<algorithm>has been pulled in.If
std::vector<int>::iterator(the type of the argument) is a class in namespacestd, thenstd::findis a match for your call even though you never “used” it, so the call is ambiguous.If
std::vector<int>::iteratorisint*, thenstd::findis not a candidate and the call is not ambiguous.Either way is a valid implementation of
std::vector, and it’s also implementation-defined whether or not either<iostream>or<vector>includes<algorithm>. So your code isn’t portable, but implementations are pretty much incapable of diagnosing the portability issue unless the code actually fails on that implementation.In more typical cases of ADL, the function or function template in the associated namespace is a better candidate (more specific) than the one in the namespace that the caller inhabits or “uses”, so ambiguity is avoided. But your global
findis basically identical tostd::find, so that doesn’t apply.http://ideone.com/Cskur:
Result:
Conclusion: it is somewhat dangerous to use names from
std, even in other namespaces.Or if you prefer: defining names from
stdin other namespaces may mean that callers need to be careful. The difference is mostly a matter of who fixes the bug when it happens.