Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

VC appears to disable argument-dependent lookup, when using std::swap

33 views
Skip to first unread message

Niels Dekker - no return address

unread,
Dec 8, 2008, 9:09:04 AM12/8/08
to
In some cases, Visual C++ appears to disable argument-dependent lookup (ADL),
when it encounters a "using declaration" (e.g., using std::swap). In those
cases, the compiler accepts ambiguous code, without any warning. Is this a
known compiler bug?

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

David Lowndes

unread,
Dec 8, 2008, 11:40:30 AM12/8/08
to
>Shall I report this issue to https://connect.microsoft.com ?

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

Igor Tandetnik

unread,
Dec 8, 2008, 11:51:51 AM12/8/08
to

... 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


Vladimir Grigoriev

unread,
Dec 8, 2008, 1:28:52 PM12/8/08
to

"Niels Dekker - no return address" <unk...@this.is.invalid> wrote in
message news:u%23JhI6TW...@TK2MSFTNGP06.phx.gbl...

> 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;
> }
> //////////////////////////////////////////////
>

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


Niels Dekker - no return address

unread,
Dec 8, 2008, 1:48:57 PM12/8/08
to
>> // 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;
>> }
>> //////////////////////////////////////////////
>
> 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

Vladimir Grigoriev

unread,
Dec 8, 2008, 1:59:30 PM12/8/08
to

"Niels Dekker - no return address" <unk...@this.is.invalid> wrote in
message news:eO5$iWWWJH...@TK2MSFTNGP06.phx.gbl...

>>> // 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;
>>> }
>>> //////////////////////////////////////////////
>>
>> 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.
>

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


Igor Tandetnik

unread,
Dec 8, 2008, 2:59:11 PM12/8/08
to
Vladimir Grigoriev <vlad....@mail.ru> wrote:
> "Niels Dekker - no return address" <unk...@this.is.invalid> wrote in
> message news:eO5$iWWWJH...@TK2MSFTNGP06.phx.gbl...
>> 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.
>
> 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.

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...

Niels Dekker - no return address

unread,
Dec 8, 2008, 5:10:08 PM12/8/08
to
Igor Tandetnik wrote:
> 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

0 new messages