简体   繁体   中英

C++: Compiling unused classes

There is a pattern that I like using for implementing factory classes that goes as follows (taken from my answer to this question):

class Factory
{
public:
    template<class DerivedType>
    DerivedType::CreatedType *createType()
    {
        DerivedType::CreatedType *r = (DerivedType::CreatedType) (*(m_creators[DerivedType::id]))();
        return r;
    }
protected:
    static std::map<int,void *(*)()> m_creators;
};

std::map<int,void *(*)()> Factory::m_creators = std::map<int,void*(*)()>();

template<class Derived, class CreatedType>
class CRTPFactory : public Factory
{
    typedef typename CreatedType CreatedType;
public:
    static bool register() 
    {
        Factory::m_creators.push_back(std::make_pair(Derived::id,Derived::create);
        return true;
    }

private:
    static bool m_temp;
};

template<class Derived>
bool CRTPFactory<Derived>::m_temp = CRTPFactory<Derived>::register();

class AFactory : public CRTPFactory<AFactory,A>
{
private:
    static A *create() 
    {
        //do all initialization stuff here
        return new A;
    }

public:
    static const int id = 0;
};

This allows extension of the factory for new types without having to change the factory class. It also allows for implementing specific creation algorithms for different types without having to change the factory class. There is a major problem with this pattern though. The class AFactory is never used explicitly. It registers its creator function at load time through CRTPFactory's member temp. This might be a little complicated to understand but it's very easy to use. The problem is AFactory isn't compiled so it's static parameters aren't initialized at load time. My question is, is it possible to force the compiler (I'm using VS 2012 but answers for GCC are also good) to compile AFactory without ever explicitly creating an instance of it? A solution that I use in VS is to dllexport AFactory, that way the compiler compiles the class even though it doesn't know of anyone instantiating it. This is because it assumes some other dll might instantiate it. The problem with this solution is that the factory class must be implemented in a separate dll as the rest of the code. And also this doesn't work on GCC.

Inheriting from CRTPFactory<AFactory,A> causes implicit instantiation of the class, but not the definitions of its members.

[temp.inst]

The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, member classes, static data members and member templates;

Instead of inheriting from CRTPFactory<AFactory,A> , you can simply explicitly instantiate the m_temp member.

template bool CRTPFactory<AFactory,A>::m_temp;

For reference, here's the modified example (in a form that compiles):

#include <map>

class Factory
{
public:
    template<class DerivedType, class CreatedType>
    CreatedType *createType()
    {
        CreatedType *r = (CreatedType) (*(m_creators[DerivedType::id]))();
        return r;
    }
protected:
    static std::map<int,void *(*)()> m_creators;
};

std::map<int,void *(*)()> Factory::m_creators = std::map<int,void*(*)()>();

template<class Derived, class CreatedType>
class CRTPFactory : public Factory
{

public:
    static bool register_() 
    {
        Factory::m_creators.insert(std::make_pair(Derived::id,Derived::create));
        return true;
    }

  static bool m_temp;
};

template<class Derived, class CreatedType>
bool CRTPFactory<Derived, CreatedType>::m_temp = CRTPFactory<Derived, CreatedType>::register_();

struct A
{
};

class AFactory
{
public:
    static void *create() 
    {
        //do all initialization stuff here
        return new A;
    }

public:
    static const int id = 0;
};

template bool CRTPFactory<AFactory,A>::m_temp;

Static class member should be explicitly created somewhere.

Doing something like this in a cpp file of your choice should work:

int AFactory::id = 0

You're mistaken in your assumption. class AFactory is definitely compiled. Quite a few times, probably, since it's in a header.

Your real problem is probably that class AFactory is not registered . Why would it be? Which statement would cause it to be? Every statement is ultimately called either from main() or from the initializer of a global variable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM