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.
CodePudding user response:
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.
This is not correct.
template struct S<U, 42>; // spec-1
Is not a specialization at all, but an explicit instantiation.
It just tells the compiler to emit the same instantiation of S
with parameters T=U
and V=42
that would have been emitted if you referred to S<U, 24>
in any other context.
A specialization as an incomplete type looks like
template <> struct S<U, 42>;
CodePudding user response:
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.
This is specified in temp.explicit-12 which states that:
An explicit instantiation definition that names a class template specialization explicitly instantiates the class template specialization and is an explicit instantiation definition of only those members that have been defined at the point of instantiation.
(emphasis mine)
And since spec-1
is an explicit instantiation definition, the result will be the instantiation of the class template specialization S<U, 42>
Is decl-1 considered a function template for the purposes of overload resolution?
No, decl-1
is a definition for an ordinary(non-template) function. Moroever, this decl-1
is nothing but the definition for the function declared in decl-2
.