1

I was trying to understand how c++ template deals with name lookup and read this thread on stackoverflow:

2 phase lookup example

Then I tried myself, as below:

#include<iostream>
using namespace std;
void bar (int){cout<<"int\n";}

template <typename T>
void foo (T const & t) {
  bar (t);
}

template <typename T>
void bar (T){cout<<"t1\n";}

namespace NS {
  struct A {};
}

int main () {
  NS::A a;
  foo (a);
}

It fails to compiler on either gcc/vc. gcc said:

<source>: In instantiation of 'void foo(const T&) [with T = NS::A]':
<source>:19:7:   required from here
<source>:7:7: error: cannot convert 'const NS::A' to 'int'
    7 |   bar (t);
      |   ~~~~^~~
      |       |
      |       const NS::A
<source>:3:11: note:   initializing argument 1 of 'void bar(int)'
    3 | void bar (int){cout<<"int\n";}
      |           ^~~

Execution build compiler returned: 1

Seems that compiler finds bar(int) and try to match foo(), not considering template bar.

But for my understanding: bar(t) uses t as dependent name, compiler shouldn't decide which bar() to use at phase 1, and should postpone to phase 2 until template instantiation, right?

Then I moved the template bar to the top of template foo then it gets compiled and run:

void bar (int){cout<<"int\n";}

template <typename T>
void bar (T){cout<<"t1\n";} // moved to here

template <typename T>
void foo (T const & t) {
  bar (t);
}

Or, If I put a none template bar inside NS, it also gets compiled:

void bar (int){cout<<"int\n";}

template <typename T>
void foo (T const & t) {
  bar (t);
}
namespace NS {
  struct A {};
  void bar (A const &){} // add this one
}

My question: what's the core difference here, why the 1st code snippet fails, and the other 2 versions OK?

Immanuel Kant
  • 517
  • 3
  • 8
  • 1
    In the second phase an unqualified dependent name can be found *only* via ADL. In the first example ADL doesn't find anything because `bar` is not in `NS`. – Evg Nov 06 '22 at 01:13

0 Answers0