Question

I have two test cases of a class having a static member instance. The first uses non-templated samples, while the second relies on generic object types.

The dilemma is simple: the constructor of the static member gets called before the main function (as it should), but only for the specific object types. The generic types do not exhibit the same behaviour. As the matter of fact, the constructor isn't compiled at all. It seems the compiler decided to completely overlook it as a means of (not completely justified) optimization.

I would like to know what is happening and what can be done to make it work in the most elegant way possible. I presume the obvious answer would be: use that static member somewhere in the code. I'd like not to do that, as the specific type case works without making use of that static member, apart from performing some "work" in its constructor.

The code samples:

//////////////////////////////////////////////
// Specific case
//////////////////////////////////////////////
class CPassive
{
public:
    CPassive()
    {
        printf(" passively called ");
    }
};

class CActive
{
private:
    static CPassive ms_passive;
};
CPassive CActive::ms_passive;
///////////////////////////////////////////////////////////
// GENERIC TYPES
///////////////////////////////////////////////////////////
class CSample
{
public:
    CSample()
    {
        printf("sample ");
    }
};

template <typename T>
class CGenericPassive
{
public:
    CGenericPassive()
    {
        T sample;
        printf(" generic passive .. ");
    }
private:
};

template <typename T>
class CGenericActive
{
private:
    static CGenericPassive<T> ms_passive;
};
template<typename T>
CGenericPassive<T> CGenericActive<T>::ms_passive;

int main(int argc, char** argv)
{
    CActive activeExample;// instantiates the static member
    CGenericActive<CSample> activeExample; // obliterates the static from the class def.
}
Was it helpful?

Solution

Each (non-virtual) member of each class template you want instantiated needs to be referenced from non-template code, directly or indirectly. It is not enough to instantiate the class itself.

This is governed by the standard 14.7.1/2:

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; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.

In your case it is enough to reference the member from CGenericActive constructor (you need to write this constructor obviously), like this:

CGenericActive()
 {
   // just reference it so it gets instantiated
   (void)ms_passive;
 }

Full live example.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top