This issue appeared during the development of the boost::swap utility. A
preliminary version of this utility had a so-called "ADL barrier namespace",
swap_adl_barrier, to prevent ambiguity:
http://svn.boost.org/svn/boost/sandbox/swap/boost/utility/swap.hpp
But unfortunately, this "ADL barrier" only worked on MSVC, because of the
compiler bug! Other compilers still applied ADL, when doing "using
std::swap", even while there was this swap_adl_barrier namespace. And those
compilers appear to be right! For more information, read the following
thread: "[boost][swap] How to fix ADL barrier for XL, Intel, GCC, Sun and
Como?", July 2008, http://thread.gmane.org/gmane.comp.lib.boost.devel/178164
Luckily boost::swap is fixed now, as Steven Watanabe came up with a better way
to avoid ambiguity. But that's beyond the scope of this posting.
Another example of the compiler bug: The following program should be rejected,
because it is ambiguous. Instead, it is accepted by MSVC (up to MSVC 2008
SP1), and Bar::Func(Foo::FooStruct) is called.
//////////////////////////////////////////////
// Example by my collegue Jeroen Eggermont
namespace Foo {
struct FooStruct {};
void Func(FooStruct);
}
namespace Bar {
void Func(Foo::FooStruct) {}
void Func(); // This overload is essential!
}
int main() {
using Bar::Func;
Foo::FooStruct fooStruct;
Func(fooStruct); // Ambiguous, but accepted!
return 0;
}
//////////////////////////////////////////////
Shall I report this issue to https://connect.microsoft.com ?
Kind regards,
--
Niels Dekker
http://www.xs4all.nl/~nd/dekkerware
Scientific programmer at LKEB, Leiden University Medical Center
If you're certain it's an issue (as you appear to be), and you can't
find it already reported, then certainly do so.
Dave
... and post the link here, so interested parties could validate it.
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Sorry I do not see ambiguous in this example. Only one name Bar::Func is
done acceptable for the main code. So IHMO it is correctly that the
Bar::Func( Foo::FooStruct ) is called. Am I wrong?
Vladimir Grigoriev
The compiler should also consider Foo::Func(FooStruct), as this function can
be found by argument-dependent lookup (ADL). And as Foo::Func(FooStruct) and
Bar::Func(Foo::FooStruct) match equally well, the function call is ambiguous.
David Lowndes wrote:
> If you're certain it's an issue (as you appear to be), and you can't
> find it already reported, then certainly do so.
Thanks, Dave. But please let me know if you think it's _not_ an issue.
Igor Tandetnik wrote:
> ... and post the link here, so interested parties could validate it.
Here it is. Please validate!
"Using-declaration ("using std::swap") should not disable argument-dependent
lookup"
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=387055
Kind regards, Niels
Thanks Niels. I did not read such details of the C++ standard. I think that
if a function name is already known by a compiler it will not use ADL.
Vladimir Grigoriev
You think incorrectly:
3.4.2p2 ...the set of declarations found by the lookup of the function
name is the union of the set of declarations found using ordinary
unqualified lookup and the set of declarations found in the namespaces
and classes associated with the argument types...
Thanks for the relevant Standard quote, and your validation of the
issue, Igor.
FYI, I added another example to
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=387055
As follows:
////////////////////////////////////////
#include <vector> // Essential!
#include <algorithm>
namespace MyNamespace {
template <class T> void swap(T&,T&);
class MyClass {};
}
int main() {
MyNamespace::MyClass obj;
using std::swap;
swap(obj,obj);
}
////////////////////////////////////////
Interestingly, MSVC _does_ detect the ambiguity when you remove the
"#include <vector>"!
Just in case you'd think, why would someone want to provide a generic
swap(T&,T&) in her own namespace... that's exactly what we did when
writing boost::swap! The interface of the boost::swap utility looks
very much like std::swap, but it has two extra features: it's often more
efficient than std::swap (because it internally allows ADL to find the
most appropriate swap overload), and it also supports swapping built-in
arrays. BTW, the Standard C++ Committee has agreed to also add support
for built-in arrays to std::swap.
Kind regards, Niels