Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force template instantiation via typedef : success at g++ , fail at Visual C++

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.

Bounty Reason

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.

like image 497
javaLover Avatar asked Sep 16 '19 09:09

javaLover


1 Answers

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.

like image 102
StoryTeller - Unslander Monica Avatar answered Oct 13 '22 18:10

StoryTeller - Unslander Monica