1

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.

4

3 回答 3

3

继承自CRTPFactory<AFactory,A>会导致类的隐式实例化,但不会导致其成员的定义。

[temp.inst]

类模板特化的隐式实例化导致类成员函数、成员类、静态数据成员和成员模板的声明的隐式实例化,而不是定义或默认参数的隐式实例化;

CRTPFactory<AFactory,A>您可以简单地显式实例化该m_temp成员,而不是从 继承。

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

作为参考,这是修改后的示例(以可编译的形式):

#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;
于 2013-07-04T10:00:30.490 回答
1

静态类成员应该在某处显式创建。

在您选择的 cpp 文件中执行此类操作应该可以:

int AFactory::id = 0
于 2013-07-04T09:23:03.833 回答
1

你的假设是错误的。class AFactory肯定是编译的。可能有好几次,因为它在标题中。

你真正的问题可能class AFactory是没有注册。为什么会这样?哪个语句会导致它成为?每个语句最终都从全局变量的初始化程序中调用main()或从全局变量的初始化程序中调用。

于 2013-07-04T09:40:13.933 回答