3
struct B {};
struct C : B {};
void f(B){} // worse match than A::f<C>

struct A {
    template<class T>
    void f(T v) {
        f(v); // #1
    }
};

int main()
{
    A{}.f(C{});
}

Activating ADL lookup in line #1 is as simple as

{
    using ::f;
    f(v);
}

I think the rule that makes the code fail without the using directive is:

[basic.lookup.argdep]/3 Let X be the lookup set produced by unqualified lookup and let Y be the lookup set produced by argument dependent lookup (defined as follows). If X contains

  • (3.1) a declaration of a class member, or
  • (3.2) a block-scope function declaration that is not a using-declaration, or
  • (3.3) a declaration that is neither a function nor a function template

then Y is empty. [...]

So, since a call to f found by non-ADL lookup will find A::f, which is a class member, overloads found by ADL-lookup are discarded.

Which C++ rule allows to ignore the restriction in 3.1 with the using declaration, to make the above code compile?

I think I'm completely misunderstanding the context where the rule [basic.lookup.argdep]/3 must be applied, or maybe I have a bigger and hidden hole in my understanding of the name lookup process.

Columbo
  • 60,038
  • 8
  • 155
  • 203
ABu
  • 10,423
  • 6
  • 52
  • 103
  • 1
    Well, you already have an MCVE, but I really think you could have reduced your code considerably more... – Rakete1111 Oct 28 '17 at 16:37
  • @Rakete1111 I think that is not so long considering that I need, (A) A member function, (B) A user namespace with a user defined class, (C) At least two overloads of a same operator, (D) A main function. – ABu Oct 28 '17 at 16:47
  • It's maybe not long, but it has a lot of things that are not necessary (like inheriting from a reference wrapper, `ostreamable_with`, ...) IMO. – Rakete1111 Oct 28 '17 at 17:00
  • Mind if I reduce the code for you? – Columbo Oct 28 '17 at 18:45
  • @Columbo Ok but add some kind of comment to say that the "code has been adapted to that specific question", or send me a coliru or any kind of online compiler/pastebin link to see the code first and I do the changes. As wish. – ABu Oct 28 '17 at 18:48
  • 1
    @Peregring-lk See if you like it, otherwise revert- – Columbo Oct 28 '17 at 18:58

1 Answers1

5

First paragraph on unqualified name lookup:

In all the cases listed in [basic.lookup.unqual], the scopes are searched for a declaration in the order listed in each of the respective categories; name lookup ends as soon as a declaration is found for the name.

In particular,

For the members of a class X, a name used in a member function body […], following the member's declarator-id, shall be declared in one of the following ways:

  • before its use in the block in which it is used or in an enclosing block ([stmt.block]), or

  • shall be a member of class X or be a member of a base class of X ([class.member.lookup]), or ...

A local (re)declaration of a name is prioritised and shadows all extrinsic declarations.

Columbo
  • 60,038
  • 8
  • 155
  • 203
  • Ahhh!! and then ADL lookup will found the function member again and added to the overloaded set if the number of parameters match, isn't? – ABu Oct 28 '17 at 18:45
  • @Peregring-lk Yes, the `user::operator<<` will be found via `ref`'s template argument's associated namespace. – Columbo Oct 28 '17 at 18:51
  • The `user::operator<<` is not a member function. Besides, what is `ref`? And consider the operator syntax too: `using std::operator<<; *this << v;`. – ABu Oct 28 '17 at 18:55