Let's consider simple example about template implicit instantiation:
#include <iostream>
template<int N>
class A
{
static const int a = A<N-1>::a; //1, OK, doesn't require implicit intantiation
};
template<int N>
class B
{
static const int a = B<1>::a; //2, Error, implicit instantiation of template 'B<1>' within its own definition
};
int main(){ }
DEMO
The standard wasn't clear about that fact. What it says is only that N3797::14.7.1/1 [temp.inst]:
Unless a class template specialization has been explicitly
instantiated (14.7.2) or explicitly specialized (14.7.3), 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.
Neither 1 nor 2 don't require the class type to be completely defined, however the second one causes the error about implicit instantiation. I'd like to understand why.
I think the reason B<1> fails immediately and A<N-1> not is because of temp.res#general-8.4
The validity of a template may be checked prior to any instantiation. The program is ill-formed, no diagnostic required, if:
a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter
Related
#include <iostream>
template<class T> struct A {
enum E : T;
};
template<class T> enum A<T>::E : T { eT };
template<> enum A<char>::E : char { //#1
echar
};
int main(){
}
Consider the above code which is mentioned in temp.expl.spec#6, it's a typically ill-formed code. The rule says:
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.
At the point #1, where the specialization A<char> will cause implicit instantiation
As a contrast:
#include <iostream>
template<class T> struct A {
struct Test;
};
template<typename T>
struct A<T>::Test{
};
template<>
struct A<int>::Test{ //#2
int c;
};
int main(){
}
Consider this code, At the point #2, where the specialization A<int> also cause implicit instantiation, The difference of the implicit instantiation between such two codes is said as the following:
temp.inst#2
The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, default arguments, or noexcept-specifiers of the class member functions, member classes, scoped member enumerations, static data members, member templates, and friends; and it causes the implicit instantiation of the definitions of unscoped member enumerations and member anonymous unions. However, for the purpose of determining whether an instantiated redeclaration is valid according to [basic.def.odr] and [class.mem], a declaration that corresponds to a definition in the template is considered to be a definition.
Because in the first code, the member enumeration is unscoped, hence the implicit instantiation of A<char> will also implicit instantiated the definition for enum E. As a contrast, in the second, Test is a member class, hence the implicit instantiation of specialization A<int> will only cause implicit instantiation of the declaration for member class Test rather than definition.
As a variant case of the first code:
#include <iostream>
template<class T> struct A {
enum E : T;
};
template<> enum A<char>::E : char {
echar
};
template<> enum A<int>::E : int { //#1
echar
};
int main(){
}
The difference from the first code is that there's no definition for member enumeration E of its enclosing primary class template, within the primary class template A, it's just a declaration.
So, I think the rule in [temp.expl.spec#6] is not clear. As these above codes shown, in each case, the specialization of primary class template all cause the implicit instantiation for class member, The distinction is one expect the implicit instantiation of declaration , the other is definition.
So, I think modified the rule as the following:
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 of the definition that instantiated from the definition for the corresponding entity, in every translation unit in which such a use occurs; no diagnostic is required.
It will be conform the observable result. If I miss something, please correct me.
This code fails to compile because of the inheritance from an incomplete type (https://godbolt.org/z/G35wj9):
template<typename>
class Incomplete;
class T : public Incomplete<T> {};
template<typename>
class Incomplete {};
int main()
{
[[maybe_unused]] T x;
}
I believed that this rule also applied to class templates. However, this code compiles fine (https://godbolt.org/z/cU6GNt):
template<typename>
class Incomplete;
template<int d>
class T : public Incomplete<T<d>> {};
template<typename>
class Incomplete {};
int main()
{
[[maybe_unused]] T<1> x;
}
When class templates are involved, is the base class only required to be complete at the point of instantiation?
When class templates are involved, is the base class only required to be complete at the point of instantiation?
If it's a dependent base then yes. By that virtue a compiler has no idea what Incomplete<T<d>> is at the point of template definition. After all, for some values of d we can have ourselves a specialization of Incomplete<T<d>> that is entirely different from the primary template declaration.
template<>
class Incomplete<T<0>> {};
This is not a circular dependency. Simply naming the specialization T<0> does not cause it to be instantiated. It's just a type name. But it does mean the compiler has no recourse but wait until it can check the base class is valid.
On the other hand, if the base class is not a dependent type, then using it as base would be ill-formed.
The standard covers this in [temp.inst] §1 (taken from C++17) :
Unless a class template specialization has been explicitly instantiated (17.7.2) or explicitly specialized (17.7.3), 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. [ Note: In particular, if the semantics of an expression depend on the member or base class lists of a class template specialization, the class template specialization is implicitly generated. For instance, deleting a pointer to class type depends on whether or not the class declares a destructor, and a conversion between pointers to class type depends on the inheritance relationship between the two classes involved. — end note ] [ Example:
template<class T> class B { /* ... */ };
template<class T> class D : public B<T> { /* ... */ };
void f(void*);
void f(B<int>*);
void g(D<int>* p, D<char>* pp, D<double>* ppp) {
f(p); // instantiation of D<int> required: call f(B<int>*)
B<char>* q = pp; // instantiation of D<char> required: convert D<char>* to B<char>*
delete ppp; // instantiation of D<double> required
}
— end example ] If a class template has been declared, but not defined, at the point of instantiation (17.6.4.1), the instantiation yields an incomplete class type (6.9). [ Example:
template<class T> class X;
X<char> ch; // error: incomplete type X<char>
— end example ] [ Note: Within a template declaration, a local class (12.4) or enumeration and the members of a local class are never considered to be entities that can be separately instantiated (this includes their default arguments, noexcept-specifiers, and non-static data member initializers, if any). As a result, the dependent names are looked up, the semantic constraints are checked, and any templates used are instantiated as part of the instantiation of the entity within which the local class or enumeration is declared. — end note ]
Also covered on cppreference.
Just keep in mind that a class template is not a type, and no code is generated for it. Code is generated when the template is instantiated. When a class template is instantiated (implicitly or explicitly), an actual class (type) is generated (including the code for it).
The only difference is, that in your example you use the Incomplete class inside of a template.
In the original example it was used by a class. The type of the class will be created by the compiler at this time, thus before Incomplete is defined.
In your code, Incomplete is used in another template T, (roughly speaking: T is a mold to generate various types by use of Incomplete). At this time the compiler does nothing, it just stores a "rule to generate types" (what I called the mold).
The compiler checks validity of T at the time it is used, hence at the line - then the actual type T<1> : public Incomplete gets generated.
T (the mold) is "valid" iff Incomplete is defined
[[maybe_unused]] T<1> x;
At this point the template class Incomplete is well defined, and the compiler is happy.
Is it legal to declare a reference template in C++14 without initializing the primary reference template, as long as it is never instantiated?
template<class T>
const T& ref;
template<>
auto ref<int> = 1;
auto x = ref<int>;
This produces different results on GCC and Clang:
$ g++ -std=c++14 -c ref.cpp
$
$ clang -std=c++14 -c ref.cpp
ref.cpp:2:10: error: declaration of reference variable 'ref' requires an
initializer
const T& ref;
^~~
1 error generated.
It makes no sense having to initialize the primary reference template, because until it's instantiated, it's a template, not a reference.
I have found that I can do something like:
template<class T>
const T& ref = "Meaningless initialization with any value of any type";
template<>
auto ref<int> = 1;
auto x = ref<int>;
because apparently GCC and Clang both accept but ignore the reference template initializer RHS as long as it's a valid expression and the primary reference template is never instantiated. And any expression of any type satisfies Clang's initialization requirement.
GCC does not require an initializer as long as the primary reference template is never instantiated. That seems to be the correct behavior "in spirit", because until a reference template is actually instantiated, it should not need an initializer.
The Standard isn't 100% clear on reference templates. Here's what little I could find on variable template instantiation:
14.7.1
Unless a variable template specialization has been explicitly instantiated or explicitly specialized, the variable template specialization is implicitly instantiated when the specialization is used.
...
An implementation shall not implicitly instantiate ... a variable template ... that does not require instantiation.
14.7.2
Except for inline functions, declarations with types deduced from their initializer or return value (7.1.6.4), const variables of literal types, variables of reference types, 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 (3.2) 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 ]
14.7.3
A declaration of a function template, class template, or variable template being explicitly specialized shall precede the declaration of the explicit specialization. [ Note: A declaration, but not a definition of the template is required. —end note ].
Edit to add:
A variable template declaration, class template declaration, or function template declaration, is not the same as a variable declaration, class declaration, or function declaration, respectively, and is not subject to the same rules. Until a template is instantiated, it is just a template.
Class templates, variable templates, and function templates may be declared without providing a primary definition, only specialization definitions. The following code is legal on both Clang and GCC:
// Class
template<class T> class foo; // Declaration, not definition
template<> class foo<int> {}; // Specialization definition
using ifoo = foo<int>; // Specialization instantiation
// Function
template<class T> void bar(T); // Declaration, not definition
template<> void bar(int) {} // Specialization definition
void (*barp)(int) = bar<int>; // Specialization instantiation
// Variable
int j;
template<class T> T* point; // Declaration, not definition
template<> int* point<int> = &j; // Specialization definition
int *k = point<int>; // Specialization instantiation
The question, then, is why should it be any different for a reference template? Why should the primary declaration of a reference template have to be a definition with a reference initialization, when that's not true of any other templates?
template<class T> const T& ref; // Declaration, not definition
template<> const int& ref<int> = 1; // Specialization definition
const int& iref = ref<int>; // Specialization instantiation
I believe this is covered by [temp.res]/8:
... The program is ill-formed, no diagnostic required, if:
no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated...
The reference template you've written can never yield a valid specialization, as the variable produced by an instantiation will always require an initializer.
The quotation I provided is from C++17, but there's a similar statement in C++14.
When I compile the following with g++ --std=c++98 -Wall -Werror -Wpedantic Test.cc, there's no error.
template <class T>
struct TemplateClass {
T *ptr;
TemplateClass(T *p): ptr(p) {}
int foo() {
return ptr->bar();
}
};
struct ExampleClass {
};
int main() {
TemplateClass<ExampleClass> x(new ExampleClass());
}
I expected that the compiler would complain that ExampleClass doesn't implement method bar.
But it looks like it only complains if I actually use the method foo.
Can I rely on this behavior on any C++98 and C++11 compliant compilers?
My understanding of templates before was that whenever a template is instantiated, the entirety of the body is copied with T replaced with the template argument. Is this not how templates work?
This is the correct behaviour according to the standard. The definition of foo is not instantiated until used in a context that requires it to exist. Emphasis mine in the below:
C++03, [temp.inst]/1:
The implicit instantiation of a class template specialization causes the implicit
instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, member classes, static data members and member templates; and it causes the implicit instantiation
of the definitions of member anonymous unions. Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly
instantiated when the specialization is referenced in a context that requires the member definition to exist; ...
C++11, [temp.inst]/1 and [temp.inst]/2:
Unless a class template specialization has been explicitly instantiated (14.7.2) or explicitly specialized (14.7.3),
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. The implicit instantiation of a class template specialization causes the implicit
instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, member classes, scoped member enumerations, static data members and member templates; ... Unless a member of a class template or a member template has been explicitly instantiated or explicitly
specialized, the specialization of the member is implicitly instantiated when the specialization is referenced
in a context that requires the member definition to exist; ...
If I have the following code:
template <typename T = int>
struct mystruct {
using doublestruct = mystruct<double>;
}
mystruct<>::doublestruct obj;
Does this instantiate the mystruct<int> template at all? Or only the mystruct<double> is instantiated?
Yes, it will have to instantiate mystruct<int> in order to access its members and determine the meaning of doublestruct. You could test this with a static_assert:
#include <type_traits>
template <typename T = int>
struct mystruct {
static_assert(!std::is_same<T,int>::value, "");
using doublestruct = mystruct<double>;
};
mystruct<>::doublestruct obj; // assertion fails for T==int
mystruct<char>::doublestruct obj; // OK, not instantiated for int
Yes, it must be instantiated; doublestruct is a member of the instantiation so, if you do not have an instantiation, you do not have a doublestruct.
[C++11: 14.7.1]: Unless a class template specialization has been explicitly instantiated (14.7.2) or explicitly specialized (14.7.3), 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. [..]
In particular, consider the potential effect of specialisations of mystruct that may not contain a member doublestruct, or may contain one that is not a type.