Explicit instantiation declaration with extern - c++

I am reading 14.7.2 in C++ Standard draft n3485 and it says:
2 The syntax for explicit instantiation is:
explicit-instantiation:
externopt template declaration
There are two forms of explicit instantiation: an explicit instantiation definition and an explicit instantiation declaration. An explicit instantiation declaration begins with the extern keyword.
Seeing that a template declaration and definition is always put in a header, I have never seen a declaration with extern on a template. What exactly does that bolded sentence mean?
Also why would an instantiation care about extern?

It tells the compiler not to instantiate that template in this TU.
Note that it should be instantiated in one TU (without the extern bit), if you want your code to actually link.

Related

extern keyword with specialized template declaration [duplicate]

This question already has answers here:
Explicit template instantiation - when is it used?
(4 answers)
How template explicit instantiation works and when?
(1 answer)
Closed 9 months ago.
I'm working with a code base that has the following declarations in a.cpp:
template <int num_dim = 2>
int register_parameters();
extern template int register_parameters<2>(); // why is extern required here?
In b.cpp, we define
template <int num_dim = 2> int register_parameters() {
// define stuff
}
template int register_parameters<2>();
When I remove the extern keyword, I get the following error at compile time
error: explicit instantiation of ‘int register_parameters() [with int num_dim = 2]’ but no definition available [-fpermissive]
template int register_parameters<2>();
I am wondering why the extern keyword is required in this case?
These are not specialization declarations. Explicit specialization declarations/definitions use template<> instead of template and extern can't be used on them like this.
extern template int register_parameters<2>();
is an explicit instantiation declaration.
template int register_parameters<2>();
is an explicit instantiation definition.
Normally, when the definition of a template is available, and a template specialization like register_parameters<2> is used in a way that would require a definition of that specialization to exist (e.g. a function call register_parameters<2>()), the compiler would implicitly instantiate the template definition into the definition for the specific specialization (i.e. the actual body of the function that register_parameters<2> refers to with 2 substituted for ndims from the template definition). For it to be able to do that it is usually required that the template is defined in a header file available at the point requiring the implicit instantiation.
The explicit instantiation definition instructs the compiler to explicitly instantiate the template specialization in this translation unit and guarantee that the instantiation is available to other translation units as well (so that these do not actually need an instantiation/definition).
If there is no definition for the template available, then this can of course not work. Hence your error message at the end of the question.
The explicit instantiation declaration instructs the compiler that there is a corresponding definition somewhere (else) in the program and that implicit instantiation of the template specialization should not be done and is not needed in this translation unit. It could not be done in a.cpp anyway though, since it lacks the definition of the template.
So together these two make sure that there will be exactly one single instantiation of the template specialization in the program, coming from translation unit b.cpp with the explicit instantiation definition, instead of the more common approach of having the template be defined in a header and implicitly instantiated in each translation unit.

A issue about the order of explicit instantiation and explicit specialization

#include <iostream>
template<typename T>
void func(T){}
template void func<int>(int);
template<>
void func<int>(int){
}
int main(){
}
Consider the above code, Clang and GCC both complain such code is ill-formed, as the below outcome noted.
explicit specialization of 'func<int>' after instantiation
However, I only find the similar rule :
temp.expl.spec#6
If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined.
I think such code does not violate the above rule, Note the emphasized part, it says implicit instantiation, In my example, such declaration template void func<int>(int); is a explicit instantiation definition rather than the specialization that would case an implicit instantiation, So why the above code is ill-formed? what's the rule in the standard does the above code violate? Please point the rule out. Thanks.
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. [...]

Using `extern template` to prevent implicit instantiation of a template class

Consider the following code snippet:
template <typename>
struct X { };
extern template struct X<int>;
int main()
{
X<int>{};
}
It compiles and links: live example on godbolt.org. I would expect it not to link due to the extern template declaration.
My understanding is that extern template means: "please don't instantiate this particular template specialization in this TU, it will be provided by some other TU and you can link against it".
The examples/descriptions. I've seen on isocpp and cppreference seem to validate my mental model. E.g.
From https://en.cppreference.com/w/cpp/language/class_template:
An explicit instantiation declaration (an extern template) skips implicit instantiation step: the code that would otherwise cause an implicit instantiation instead uses the explicit instantiation definition provided elsewhere (resulting in link errors if no such instantiation exists). This can be used to reduce compilation times by explicitly declaring a template instantiation in all but one of the source files using it, and explicitly defining it in the remaining file.
Why does my code snippet link? What is actually happening here?
EDIT - found this in the latest Standard draft:
[temp.explicit]
If an entity is the subject of both an explicit instantiation declaration and an explicit instantiation definition in the same translation unit, the definition shall follow the declaration. An entity that is the subject of an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit instantiation in the translation unit shall be the subject of an explicit instantiation definition somewhere in the program; otherwise the program is ill-formed, no diagnostic required.
Does this mean that the code snippet I posted is ill-formed, NDR?
Why does my code snippet link? What is actually happening here?
Well, there's nothing to link. For one has to consider the effects of the explicit instantiation. From n3337:
[temp.explicit] (emphasis mine)
10 Except for inline functions and class template
specializations, explicit instantiation declarations have the effect
of suppressing the implicit instantiation of the entity to which they
refer. [ Note: The intent is that an inline function that is the
subject of an explicit instantiation declaration will still be
implicitly instantiated when odr-used ([basic.def.odr]) so that the
body can be considered for inlining, but that no out-of-line copy of
the inline function would be generated in the translation unit. — end
note ]
So the implicit instantiation of the class template specialization X<int>, is not suppressed. It's also an aggregate, so its initialization occurs inline, and we get nothing to link against. However, if it had any members, those would be suppressed under paragraph 8:
An explicit instantiation that names a class template specialization
is also an explicit instantiation of the same kind (declaration or
definition) of each of its members (not including members inherited
from base classes) that has not been previously explicitly specialized
in the translation unit containing the explicit instantiation, except
as described below.
So if you had instead of an aggregate something akin to this:
template <typename>
struct X {
X();
};
template <typename T>
X<T>::X() {}
extern template struct X<int>;
int main()
{
X<int>{};
}
That would fail as you expect, since it ODR uses a constructor whose definition is never instantiated. The declaration is instantiated, because the enclosing specialization is instantiated, as mentioned above. But we never get any definition, under the suppressing effect of the explicit instantiation declaration.
Does this mean that the code snippet I posted is ill-formed, NDR?
Yes, by the exact sentence from [temp.explicit]/13 that you quoted. "An entity" means just that. It does not matter if an explicit instantiation declaration otherwise have no normative effect.

Are explicit template instantiation declarations required in the header when explicitly instantiating the definitions in the source file?

In this question, the accepted answer involves a template function declaration in a header file which has its definition in the source file. To make this template function also usable in other translation units, explicit template instantiations are made in the source file for each "allowed" usage. So far this appears to me as standard practice.
The answer however also recommends placing corresponding explicit template instantiation declarations in the header file. I have not seen this practice before and would like to know if this is required by the standard.
Here is a small example:
A.h
struct A
{
template<class T>
void g(T t);
};
A.cpp
#include "A.h"
template<class T>
void A::g(T t)
{ /* ... */ }
template void A::g(int); // Explicit instantiation of the definition.
main.cpp
#include "A.h"
int main()
{
A a;
a.g(0);
}
The wording in the standard does not make it clear to me whether the explicit instantiation of the declaration is also required. This seems to primarily concern the "the definition is never instantiated explicitly, an implicit instantiation in A.cpp is not guaranteed to be retained" case (not depicted), but I would appreciate clarification.
Are explicit template instantiation declarations required in the header when explicitly instantiating the definitions in the source file?
No. The rule is, from [temp]/10, emphasis mine:
A function template, member function of a class template, variable template, or static data member of a class template shall be defined in every translation unit in which it is implicitly instantiated unless the corresponding specialization is explicitly instantiated in some translation unit; no diagnostic is required.
In your example, A::g<int> is implicitly instantiated in main.cpp but it is explicitly instantiated in "some translation unit" (A.cpp). The program is fine.

template class and respective extern template class in same translation unit

Is this a correct usage of extern template in C++11? (Can it be that the extern template class and respective template class is visible in the same translation unit?)
// example.hpp:
#pragma once
template< typename T >
class C {
void f(T);
};
// question is about the next two lines
extern template class C< float >;
extern template class C< double >;
// example_def.hpp:
#include "example.hpp"
template< typename T >
void C< T >::f(T) {
//... smth. practicable
}
// example.cpp:
#include "example_def.hpp"
template class C< float >;
template class C< double >;
// other.hpp:
#pragma once
void g();
// other.cpp:
#include "other.hpp"
#include "example.hpp"
// maybe those two lines should be here instead?
void g() {
C< float >();
C< double >();
}
// main.cpp:
#include "example.hpp"
#include "other.hpp"
// ...and here?
int main() {
C< float >();
C< double >();
g();
return 0;
}
Yes, both an extern template class specification (called explicit instantiation declaration by the Standard) and a template class specification (called explicit instantiation definition by the Standard) can be in the same translation unit, if the definition (without extern) follows the declaration (with extern):
(§14.7.2/11) If an entity is the subject of both an explicit instantiation declaration and an explicit instantiation definition in the same translation unit, the definition shall follow the declaration. An entity that is the subject of an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit instantiation (14.7.1) in the translation unit shall be the subject of an explicit instantiation definition somewhere in the program; otherwise the program is ill-formed, no diagnostic required. [ Note: This rule does apply to inline functions even though an explicit instantiation declaration of such an entity has no other normative effect. This is needed to ensure that if the address of an inline function is taken in a translation unit in which the implementation chose to suppress the out-of-line body, another translation unit will supply the body. — end note ] An explicit instantiation declaration shall not name a specialization of a template with internal linkage.
(Emphasis mine). The terms explicit instantiation declaration and explicit instantiation definition are defined here:
(§14.7.2/2) The syntax for explicit instantiation is:
explicit-instantiation:
externopt template declaration
There are two forms of explicit instantiation: an explicit instantiation definition and an explicit instantiation declaration. An explicit instantiation declaration begins with the extern keyword.
The effect of these explicit instantiations is as follows:
The explicit instantiation declaration (with extern) prevents all implicit instantiations to take effect (except for inline functions and class template specializations, §14.7.2/10).
The explicit instantiation definition (without extern) causes the instantiation to happen no matter what, i.e. it overrides the explicit instantiation declaration (this also follows from §14.7.2/10).
General comments
The fact that your explicit instantiation declarations are located in the header file that defines the template implies that anyone who includes the header files in order to make use of the template will either have to also add an explicit instantiation definition, or, alternatively, needs to link to the code of another .cpp file that includes such an explicit instantiation definition.
This can be confusing and is probably not a very good idea when you expect many different users to instantiate the template for many different types. But it can be sensible if the number of instantiations for distinct types is small and you can anticipate them all. Of course you must make sure that there is one (or several) .cpp file(s) that include explicit instantiation definitions for all the instantiations required, and that its corresponding object file is linked with the project at build time.
The basic idea of extern templates is to support explicit instantiation of commonly used instantiations while also supporting implicit instantiations for less commonly used parameters. For example, std::basic_string<char> could be explicitly instaniated but std::basic_string<signed char> could be left for implicit instantiation (the actual motivating examples were IOStreams which take substantial time to get instantiated but only two instantiations are actually used).
To allow implicit instantiation the definition of the used templates needs to be visible in each translation unit where the template is used. If the template definition is visible the compiler assumes by default that it needs to provide an instantiation implicitly. Using an extern template declaration tells the compiler that the specific template instantiation will be provided by some translation unit.
Although your case works it isn't even necessary to declare the extern templates: When the compiler uses an instantiation and doesn't find its definition it will assume that the instantiation is found in some translation unit.