Question

The situation is that some member function bar::Bar::frobnicate wants to utilize ADL to find a function from some unknown namespace, within a function that has an identical name. However, it only finds its own name.

Testcase

(Note that in reality, Bar is a Foo-agnostic template; this is just the reproducible, minimal testcase)

namespace foo {
    struct Foo {};
    void frobnicate(Foo const &) {}
}

namespace bar {
    struct Bar {
        void frobnicate() {
            foo::Foo foo;
            frobnicate(foo); // <-- error
        }
    };
}

int main () {
    bar::Bar x;
    x.frobnicate();
    frobnicate(foo::Foo());
}

Results in:

test.cc: In member function ‘void bar::Bar::frobnicate()’:
test.cc:10:31: error: no matching function for call to ‘bar::Bar::frobnicate(foo::Foo&)’
test.cc:10:31: note: candidate is:
test.cc:8:18: note: void bar::Bar::frobnicate()
test.cc:8:18: note:   candidate expects 0 arguments, 1 provided

Standard

I understand that this is correct compiler behaviour:

3.4.1 Unqualified name lookup [basic.lookup.unqual]

(...) name lookup ends as soon as a declaration is found for the name (...)

and only after unqualified lookup failed, argument dependent lookup comes into play:

3.4.2 Argument-dependent name lookup [basic.lookup.argdep]

When the postfix-expression in a function call (5.2.2) is an unqualified-id, other namespaces not considered during the usual unqualified lookup (3.4.1) may be searched

Workaround

My current workaround is to introduce a special traits class that does not define the clashing name itself:

    struct BarTraits {
        void frobnicate_(foo::Foo const &b) {
            frobnicate(b);
        }
    };

or this ligher version:

    void frobnicate_(foo::Foo const &c) { frobnicate(c); }

Question

Are there better alternatives than introducing such traits classes?

Explicitly qualifying the call as foo::frobnicate(foo) is not an option here, because (as mentioned) the Bar class is a template upon Foo in reality and should not only work for types in the foo namespace.

Was it helpful?

Solution

As you found out yourself, adding a member function frobnicate to the class interface of Bar (or Bar<T> in the template case), will prevent ADL from finding foo::frobnicate.

The easiest -and in this case idiomatic- way to add frobnicate functionality to a class Bar (or to a class template Bar<T>) is to add a non-member function frobnicate(Bar) (or function template frobnicate(Bar<T>)) to the namespace bar

namespace foo {
    struct Foo {};
    void frobnicate(Foo const &)  {}
}

namespace bar {
    template<class T>
    struct Bar {    
       T t;    
    }; 

    template<class T>
    void frobnicate(Bar<T> const& b)
    {
        frobnicate(b.t);    
    }
}

int main () {
    bar::Bar<foo::Foo> x;
    frobnicate(x);
    frobnicate(foo::Foo());
}

If you insist on having a member function, you will have to rename it to something like do_frobnicate(). I would not use type traits tricks to get the same behavior as it is an indirect approach, and makes the class interfaces much harder to understand (remember Stroustrup's motto: "represent your ideas directly in code").

OTHER TIPS

you can use this trick

namespace dummy { void your_func(may be some parameteres); }
struct bar { 
   void member() {
      using dummy::your_func; // now your call will find that and ADL will kick in

I just do it with a proxy function

namespace utils 
{
int lookup_adl(int arg) 
{
  return lookup(arg);// ADL search
}
struct Foo 
{
  int lookup(int arg) { return ::utils::lookup_adl(arg);}
};
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top