1

Can one show me an example of ADL without using templates? Never seen something like that. I mean something like here. Specifically I am interested in example in which it leads to some pitfall like in mentioned.

EDIT:

I think Tomalak's answer can be extended to pitfall. Consider this:

namespace dupa {

    class A {
    };

    class B : public A {
    public:
        int c;
        B() {
        }
    };

   void f(B b) {
       printf("f from dupa called\n");
   }
}

void f(dupa::A) {
    printf("f from unnamed namespace called\n");
}


int main()
{   
    dupa::B b;
    f(b);

    return 0;
}

Here we expect that f from unnamed namespace will be called, but instead another one is called.

Community
  • 1
  • 1
Argbart
  • 73
  • 5

3 Answers3

4

I can't show you something leading to a pitfall, but I can demonstrate ADL working without templates:

namespace foo {
   struct T {} lol;
   void f(T) {}
}

int main() {
   f(foo::lol);
}

Note that lol's type has to be a class-type; I originally tried with a built-in, as you saw, and it didn't work.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
2

The trick to get confusion is creating an scenario where the arguments to the function are interchangeable or convertible and that ADL might pick something that might not be what you would expect. I am not sure if this is impressive or just expected:

namespace a {
   struct A {};
   void f( A* ) { std::cout << "a::f" << std::endl; }
}
namespace b {
   struct B : ::a::A {};
   void f( B* ) { std::cout << "b::f" << std::endl; }
}

void test() {
   f( new b::B );     // b::f
   a::A* p = new b::B; 
   f( p );            // a::f
}

The types are the same, but ADL will check the static type of the argument and add that namespace into the search. That in turn means that the exact static type might make different functions visible to the compiler. Things can be more confusing when there are more than one argument on which ADL or overload resolution can apply .

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • Note that the effect is exactly the same of having non-virtual methods: the static type determines which of the methods is used in overloading, and that is by design: ADL is in the language so that free functions can be used as extensions to a type in a way *similar* to member functions. – David Rodríguez - dribeas Jul 13 '11 at 22:07
2

No templates.
Using swap() because that is the most common usage.

#include <iostream>

namespace One
{
    class A {};
    void swap(A& lhs, A& rhs) { std::cout << "Swap-One A\n";}
}

namespace Two
{
    class A {};
    void swap(A& lhs, A& rhs) { std::cout << "Swap-Two A\n";}
}


int main()
{
    One::A      oneA_l;
    One::A      oneA_r;
    Two::A      twoA_l;
    Two::A      twoA_r;

    swap(oneA_l, oneA_r);
    swap(twoA_l, twoA_r);
}
Martin York
  • 257,169
  • 86
  • 333
  • 562