C ++:编译未使用的类

时间:2013-07-04 09:16:48

标签: c++ templates design-patterns compiler-construction

我喜欢使用一种模式来实现工厂类,如下所示(取自我对this问题的回答):

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;
};

这允许扩展工厂的新类型,而无需更改工厂类。它还允许为不同类型实现特定的创建算法,而无需更改工厂类。但是这种模式存在一个主要问题。从未明确使用AFactory类。它通过CRTPFactory的成员temp在加载时注册其创建者函数。这可能有点复杂,但它很容易使用。问题是AFactory没有编译,所以它的静态参数在加载时没有初始化。我的问题是,是否有可能强制编译器(我使用VS 2012但GCC的答案也很好)来编译AFactory而没有明确地创建它的实例? 我在VS中使用的解决方案是dllexport AFactory,这样编译器就可以编译类,即使它不知道任何实例化它的人。这是因为它假设其他一些dll可能会实例化它。此解决方案的问题是工厂类必须作为其余代码在单独的dll中实现。而且这对GCC也不起作用。

3 个答案:

答案 0 :(得分: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;

答案 1 :(得分:1)

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

在你选择的cpp文件中做这样的事情应该有效:

int AFactory::id = 0

答案 2 :(得分:1)

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

您真正的问题可能是class AFactory已注册。为什么会这样?哪个陈述会导致它?每个语句最终都来自main()或来自全局变量的初始值设定项。