I am learning forcing template instantiantion.
It works, but I am still curious :-
#include <iostream>
#include <string>
template <typename T, T>struct NonTypeParameter { };//#1#
int lala=0;
template <typename T> class InitCRTP{
public: static int init;
public: using dummy=NonTypeParameter<int&, init>; //#2#
};
template <typename T> int InitCRTP<T>::init = lala++;
class WantInit : public InitCRTP<WantInit>{
};
int main(){
std::cout << lala << std::endl;
}
It prints 1, because InitCRTP<WantInit>::init
is instantiated correctly.
Observation
#2#
, it will print 0. (InitCRTP<WantInit>::init
is not instantiated). If I change #2#
from int&
to int
, I will get :-
error: the value of 'InitCRTP::init' is not usable in a constant expression
If I change #1#
to template <T>struct NonTypeParameter { };
and #2#
to public: using dummy=NonTypeParameter<init>;
I will get :-
error: 'T' has not been declared
Why the line #2#
is enough to force instantiation?
In my opinion, it is just a typedef within template class that is not accessed by anyone.
Why do I need int&
as another template parameter to make it compilable?
A probably more correct question : What is the name of the technique?
Original post : Force explicit template instantiation with CRTP
Why the line #2# is enough to force instantiation?
To supply the second argument, the compiler has to bind a reference. Meaning it ODR-uses the static variable, so the variable has to exist and have a unique identity. Ergo, its definition is instantiated.
When you use plain int
, the second parameter can only accept integer constant expressions. A non-const static is not usable in a constant expression.
Why do I need
int&
as another template parameter to make it compilable?
You need to declare the type of the reference for the second parameter to have a type the compiler can check against. Well, prior to C++17 you needed to anyway. Nowadays we can use a placeholder type instead.
template <auto&>struct NonTypeParameter { };//#1#
using dummy=NonTypeParameter<init>;//#2#
That will ODR-use the passed in static without having to specify a reference type explicitly.