I want to force template instantiation.
The below code works (print 1
) at g++ ( http://coliru.stacked-crooked.com/a/33986d0e0d320ad4 ).
However, it prints wrong result (0
) at Visual C++ ( https://rextester.com/WGQG68063 ).
#include <iostream>
#include <string>
template <int& T>struct NonTypeParameter { };
//internal implementation
int lala=0;
template <typename T> struct Holder{
static int init;
};
template <typename T> int Holder<T>::init = lala++;
//tool for user
template <typename T> struct InitCRTP{
using dummy=NonTypeParameter<Holder<T>::init>;
};
class WantInit : public InitCRTP<WantInit>{};//user register easily
int main(){
std::cout << lala << std::endl;
}
Is it a Visual C++ compiler bug, or a kind of undefined behavior?
If it is Visual C++ bug, how to workaround it (while still keep it beautiful)?
Edit: Change class -> struct as Max Langhof (and many people) recommended. Thank.
With opposite solutions from StoryTeller and Maxim Egorushkin and their in-depth discussion (thank!), this sounds like a fuzzy area of C++ rule.
If it is Visual C++ bug, I wish the issue to be certain enough to report.
Moreover, I still wish for a nice workaround, because this technique is very shiny for custom type-id generation. Explicit instantiation is not so convenient.
Note: I awarded bounty to Kaenbyou Rin, because, for me, it is easy to understand.
It doesn't means that the rest of answers are less correct or less useful.
I am still not sure which is a correct one. Readers should proceed with caution.
For safety, I will assume that I just can't use the feature (for now). Thanks everyone.
There is a compiler bug involved, for sure. We can verify it by changing InitCRTP
a bit:
template <typename T, typename = NonTypeParameter<Holder<T>::init>>
struct InitCRTP {
};
Now referring to any InitCRTP<T>
specialization must use Holder<T>::init
to determine the second template argument. This in turn should force an instantiation of Holder<T>::init
, and yet VS doesn't instantiate that.
In general, using the CRTP class as a base should have instantiated all the declarations inside the class, including that of dummy
. So that too should have worked.
We can verify it further. Declarations of member functions are instantiated along with the class, when used as a base:
template <typename T> struct InitCRTP{
using dummy=NonTypeParameter<Holder<T>::init>;
void dummy2(dummy);
};
Still, VC++ is stubborn. Given all of this, and the behavior exhibited by both Clang and GCC, this is a VC++ bug.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With