Consider the following example:
#include <iostream>
template <class T, int V>
struct S
{
friend int Func(T) // decl-1
{
return V;
}
};
struct U
{
friend int Func(U); // decl-2
};
template struct S<U, 42>; // spec-1
int main()
{
std::cout << Func(U{}) << std::endl; // Compiles and prints 42
}
My understanding is that the expression Func(U{})
causes an unqualified name lookup of the function Func
, and through ADL finds declaration decl-2. However, this is not a viable candidate function for overload resolution (since it is not defined), and thus the compiler selects declaration decl-1. Misunderstanding, and irrelevant to the question, see comment from @LanguageLawyer
My question is what rule(s) in the standard allow the compiler to use the template parameters from the specialization spec-1 to instantiate the class template that contains decl-1.
Searching through cppreference, the only rule I found that seems to apply refers to overload resolution of function templates, and to cite:
For function templates, template argument deduction and checking of any explicit template arguments are performed to find the template argument values (if any) that can be used in this case:
- if both succeeds, the template arguments are used to synthesize declarations of the corresponding function template specializations, which are added to the candidate set, and such specializations are treated just like non-template functions except where specified otherwise in the tie-breaker rules;
- if argument deduction fails or the synthesized function template specialization would be ill-formed, no such function is added to the candidate set.
Source: https://en.cppreference.com/w/cpp/language/overload_resolution#Details
Is decl-1 considered a function template for the purposes of overload resolution? Does the compiler synthesize a declaration template int Func<U, 42>(U)
using spec-1 (through template argument deduction, presumably)? Or is something else at play here?
EDIT: An additional misconception that I may have is what exactly is spec-1, my current understanding is that it is the declaration of an explicit specialization of class template S
as an incomplete type, if possible please clarify if this is correct.