Rafał Janicki
Rafał Janicki

Reputation: 3

Template class automatic registration, VS 2017 compiler removes static member

I have problem with VS 2017 community C++ compiler. It removes static members from template class. All works fine in VS 2013.

I want to add static member [s] to classes. Creation of that member will register class (add it to linked-list). I also want it to work with template classes. In code bellow i have 4 classes: C1, C2< int >, C2< long >, C3. In VS2013 all 4 classes are registered but in VS 2017 C2< long > is not and C2< int > is registered only because i use that static member in printf call. Is there a way to tell compiler, that this static member should not be "optimzed".

struct iS {
    iS *next;
    static iS *first;
    virtual void CallStaticFoo() = 0;
    iS() { next = first; first = this; }
    static void CallAllFoo()
    {
        for (auto f = first; f; f = f->next)
            f->CallStaticFoo();
    }
};
iS * iS::first = nullptr;

template <class T> struct S : public iS {
    void CallStaticFoo() { T::StaticFoo(); }
};

class C1 {
public:
    static void StaticFoo() { printf("[C1: %llx]\n", reinterpret_cast<unsigned long long>(s.next)); }
private:
    static S<C1> s;
};
S<C1> C1::s;

template <typename T> class C2 {
public:
    T x;
    static void StaticFoo() { printf("[C2: %llx]\n", reinterpret_cast<unsigned long long>(s.next)); }
    //private:
    static S<C2> s; // 's' will be private member
};
template <typename T> S<C2<T> > C2<T>::s;

class C3 {
public:
    static void StaticFoo() { printf("[C3: %llx]\n", reinterpret_cast<unsigned long long>(s.next)); }
private:
    static S<C3> s;
};
S<C3> C3::s;

int main()
{
    C1 c1;
    C2<int> c2_1;
    C2<long> c2_2;
    c2_1.x = 1;
    c2_2.x = 3;
    auto y = c2_2.x - c2_1.x;
    printf("[%d]\n", y);
    iS::CallAllFoo(); 

// *** problem: if i comment line be;;pw, C2<int> is not registered.
//    static member *s* is removed by compiler.
    printf("--- %llx\n", reinterpret_cast<unsigned long long>(c2_1.s.next)); 
//  printf("--- %llx\n", reinterpret_cast<unsigned long long>(c2_2.s.next)); 

    return 0;
}

Classes description: iS - linked list entry. It is used to call StaticFoo for every registered class. For this it has static method CallAllFoo. S - used as static member of class. It add class to linked list. C1 - normal class with S as static member. Registration for this class works always. C2 - template class. Registration works only in VS 2013 or if i use static member in code. C3 - same as C1 but it is not used. Still registration works.

Upvotes: 0

Views: 55

Answers (1)

Mihayl
Mihayl

Reputation: 3911

You need explicit template instantiations for all types you want to have registered like this:

template class C2<int>;
template class C2<long>;

Otherwise the compiler will not create classes, and their corresponding static variables, out of the templates that you do not use. Why pay for something you do not use and how should the compile know with which types should it create classes out of your templates.

In this online demo you can see that no code is generated for the line template <typename T> S<C2<T> > C2<T>::s;if you comment the explcit instantiations and the call c2_1.s.next (lines 58, 59 and 54).

The Visual Studio C++ compiler is getting more standard conform.

Upvotes: 1

Related Questions