c++templatesargument-dependent-lookup

Argument-dependent lookup for built in types vs user-defined types


My code:

template <typename T>
void func(T v)
{
    func2(v);
}
    
struct S {};
    
void func2(int) {}
void func2(S) {}
    
int main()
{
    func(1);  // error here
    func(S{}); // OK
}

The error:

<source>: In instantiation of 'void func(T) [with T = int]':
<source>:14:9:   required from here
   14 |     func(1);  // error here
      |     ~~~~^~~
<source>:4:10: error: 'func2' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
    4 |     func2(v);
      |     ~~~~~^~~
<source>:10:6: note: 'void func2(S)' declared here, later in the translation unit
   10 | void func2(S) {}
      | 

Why does the lookup fail for func2 with built in types but not user-defiened?


Solution

  • Fundamental types are not considered for ADL. From cppreference

    Otherwise, for every argument in a function call expression its type is examined to determine the associated set of namespaces and classes that it will add to the lookup.

    1. For arguments of fundamental type, the associated set of namespaces and classes is empty.

    So func2(int); has an empty set and thus the compiler error.

    For the class case we have

    1. For arguments of class type (including union), the set consists of:

      a) The class itself.

      b) If the class is complete, all of its direct and indirect base classes.

      c) If the class is a member of another class, the class of which it is a member.

      d) The innermost enclosing namespaces of the classes added to the set.

    and it is item d that brings in void func2(S) {} since it is in the same namespace as S.