Template specialization and instantiation
"Instantiating a template specialization" typically refers to the process of implicit instantiation: substituting specific template arguments into a template definition to obtain an instantiated class, function, etc. Instantiating a template means instantiating a specialization of that template. Usually, the less precise phrasing is used when we're talking about some arbitrary instantiation in the context of language lawyering. You will also find the expression "instantiation of a template", which is synonymous with the instantiated specialization.
A issue about the order of explicit instantiation and explicit specialization
It's a bit fragmented, but the relevant rule here is [temp.spec]/5
For a given template and a given set of template-arguments, [...]
- both an explicit instantiation and a declaration of an explicit specialization shall not appear in a program unless the explicit instantiation follows a declaration of the explicit specialization. [...]
When a template is instantiated?
The general rule for implicit instantiation of class templates is as follows
[temp.inst]
2 Unless a class template specialization is a declared specialization, the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program. [...]
That in conjunction with this requirement about functions:
[dcl.fct.def.general] (emphasis mine)
2 In a function-definition, either void declarator ; or declarator ; shall be a well-formed function declaration as described in [dcl.fct]. A function shall be defined only in namespace or class scope. The type of a parameter or the return type for a function definition shall not be a (possibly cv-qualified) class type that is incomplete or abstract within the function body unless the function is deleted ([dcl.fct.def.delete]).
Tells us all we need to know to examine your program. Functions declarations don't require the class type to be complete. So...
Pow<double>
instantiated here?
No. This is a function declaration that is not a definition. It does not require a complete class type for a parameter. Pow<double>
is not implicitly instantiated.
Pow<int>
instantiated here?
Yes. This is a function definition, and so an instantiation is required.
Pow<int> pi;
// instantiated here?
Was already instantiated due to the function.
So when exactly the template is instantiated?
Strictly when required in a way that affects the semantics of the program.
So is
Pow<int>
instantiated whenfunc(Pow<int>)
is declared?
When func(Pow<int>)
is defined.
If I didn't use
Pow<int>
inmain()
then has it been instantiated because of its usage infunc
as the the type of its parameters?
Yes, because you did so in a function definition.
Implicit instantiation of specialization
This is a similar question here.
And now,I try to answer this question again.
A template is a type of infinite, so we can not instantiate a template, we can only be instantiated template specialization.
Implicitly instantiated, the current compilation unit requires the use of the template code, the compiler automatically instantiated template specialization.
Explicitly instantiated, we manually enter the code causes the compiler to instantiate a template specialization.
- explicit specialization, given all the template parameters, and gives a non-generic code. Once the template type match, then instantiate this specialization.
- Partial specialization, some parameters are given template and gives a non-generic code. Once the template type match, then instantiate this specialization.
Why does Clang prefer the primary template over the specialization from C++17?
This is because C++17 allowed a template type argument to be deduced from the type of a non-type argument. [temp.deduct.type]/13:
When the value of the argument corresponding to a non-type template
parameterP
that is declared with a dependent type is deduced from
an expression, the template parameters in the type ofP
are deduced
from the type of the value.
So when we try to match S<int const, nullptr>
against the partial specialization, we deduce the partial specialization's template parameter T
from two sources:
- From the first template argument
int const
, we deduceT
=int const
- From the second template argument (which has type
void (*)(int)
because the top-level cv-qualification of function parameters are adjusted away), we deduceT
=int
.
Since we deduced conflicting results, the deduction fails and the partial specialization is not a match.
Similar examples were brought up on the core reflector back in 2019. There was some agreement that this was a defect in the standard, and that deduction from the type of a non-type template argument should only happen for things that are not otherwise deducible.
Related Topics
Constexpr Initializing Static Member Using Static Function
5 Years Later, Is There Something Better Than the "Fastest Possible C++ Delegates"
Common Reasons for Bugs in Release Version Not Present in Debug Mode
Why Reference Size Is Always 4 Bytes - C++
Logical And, Or: Is Left-To-Right Evaluation Guaranteed
Blur Effect Over a Qwidget in Qt
How to Build Cmake Externalproject While Configurating Main One
Non-Copyable Elements in Vector
G++ Does Not Show a 'Unused' Warning
What Exactly Does Stringstream Do
C++ Templates Specialization Syntax
C++ Lambdas How to Capture Variadic Parameter Pack from the Upper Scope
How to Make Visual Studio Use the Native Amd64 Toolchain
Acquire/Release Semantics with Non-Temporal Stores on X64
How to Add and Subtract 128 Bit Integers in C or C++ If My Compiler Does Not Support Them
Why Does a Std::Atomic Store with Sequential Consistency Use Xchg