For the first sample, MinGW is correct and MSVC is incorrect: the get_num
call can only consider the function template.
This is a question of overload resolution, so I'll start in clause [over]. get_num(*this)
is a plain function call expression, so [over.call.func] applies:
In unqualified function calls, the name is not qualified by an ->
or .
operator and has the more general form of a primary-expression. The name is looked up in the context of the function call following the normal rules for name lookup in function calls. The function declarations found by that lookup constitute the set of candidate functions.
"Name lookup" is discussed in section [basic.lookup]. Paragraph 2:
A name "looked up in the context of an expression" is looked up as an unqualified name in the scope where the expression is found.
One complication here is that the get_num(*this)
default member initializer expression doesn't get used by anything until the default constructor of Foo
is implicitly defined by its odr-use in main
. But the lookup is determined from the code location of the expression itself, no matter that it's used in the process of that implicit definition.
For the second code sample, MinGW is again correct: the apparently recursive call inside the template definition actually calls the non-template function.
This is a result of "two phase lookup" for dependent function calls, described in section [temp.dep.res]. Briefly, since the type of t
depends on a template parameter, the name get_num
in the expression get_num(t)
is considered a dependent name. So for each instantiation of the function template, it gets two ways of finding candidates for overload resolution: the ordinary immediate way which finds the get_num
function template, plus another lookup from the point of instantiation. The specialization get_num<Foo>
has point of instantiation right after the main()
definition, so overload resolution is able to find the non-template from the instantiation context, and the non-template wins overload resolution.
(Argument-dependent lookup is a related tangent issue to this second point. ADL applies to declarations from the instantiation context but not declarations from the definition context. But it's not directly a reason for the behaviors in either example program.)
None of this has changed significantly between C++14 and the latest draft, as far as I can see.