Reading questions, comments and answers on SO, I hear all the time that MSVC doesn’t implement two-phase template lookup / instantiation correctly.
From what I understand so far, MSVC++ is only doing a basic syntax check on template classes and functions and doesn’t check that names used in the template have atleast been declared or something along those lines.
Is this correct? What am I missing?
I’ll just copy an example from my “notebook”
The above code is supposed to compile in a standard C++ compiler. However, MSVC (2005 as well as 2010 Express) will report an error because of incorrect implementation of two-phase lookup.
And if you look closer, the issue is actually two-layered. At the surface, it is the obvious fact that Microsoft’s compiler fails to perform early (first phase) lookup for a non-dependent expression
foo(0). But what it does after that does not really behave as a proper implementation of the second lookup phase.The language specification clearly states that during the second lookup phase only ADL-nominated namespaces get extended with additional declarations accumulated between the point of definition and point of instantiation. Meanwhile, non-ADL lookup (i.e. ordinary unqualified name lookup) is not extended by the second phase – it still sees those and only those declarations that were visible at the first phase.
That means that in the above example the compiler is not supposed to see
void foo(int)at the second phase either. In other words, the MSVC’s behavior cannot be described by a mere “MSVC postpones all lookup till the second phase”. What MSVC implements is not a proper implementation of the second phase either.To better illustrate the issue, consider the following example
Note that even though
bar(t)call inside the template definition is a dependent expression resolved at the second lookup phase, it should still resolve tovoid bar(void *). In this case ADL does not help the compiler to findvoid bar(N::S *s), while the regular unqualified lookup is not supposed to get “extended” by the second phase and thus is not supposed to seevoid bar(N::S *s)either.Yet, Microsoft’s compiler resolves the call to
void bar(N::S *s). This is incorrect.The problem is still present in its original glory in VS2015.