Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 对象为模板时的静态构造_C++_Gcc_Mingw32 - Fatal编程技术网

C++ 对象为模板时的静态构造

C++ 对象为模板时的静态构造,c++,gcc,mingw32,C++,Gcc,Mingw32,我有一个工厂类,我已经使用了很长一段时间了,我试图对它做一些模板魔术,但它根本不起作用。我认为您不需要查看该类,因为它相当大,但是如果您真的认为它是相关的,那么我将在中编辑它。无论如何,我有一个这样的设置,我已经做了永远 class Base : public Factory<Base> { }; class Derived : public Base { static Factory<Base>::DerivedRegister<Deri

我有一个工厂类,我已经使用了很长一段时间了,我试图对它做一些模板魔术,但它根本不起作用。我认为您不需要查看该类,因为它相当大,但是如果您真的认为它是相关的,那么我将在中编辑它。无论如何,我有一个这样的设置,我已经做了永远

class Base :
    public Factory<Base>
{
};

class Derived :
    public Base
{
    static Factory<Base>::DerivedRegister<Derived> m_Reg;
};

Factory<Base>::DerivedRegister<Derived> Derived::m_Reg;
类库:
公共工厂
{
};
派生类:
公共基地
{
静态工厂::派生寄存器m_Reg;
};
工厂::派生寄存器派生::m_Reg;
工厂为其提供静态方法createInstance(const std::string&name),该方法将返回注册对象的实例。DerivedRegister对象派生自工厂对象,当静态声明时,必须在静态初始化期间构造。这意味着我可以访问它的构造函数中的工厂静态内部构件,因此我利用它的构造函数在静态初始化期间使工厂可以使用所有注册的对象。这是可行的,并且已经有一段时间了,但我尝试了类似的方法,这样派生类就可以避免显式生成静态derivedregister对象:

class Base :
    public Factory<Base>
{
};

template<class TDerived>
class BaseReg :
    public Base
{
    static Factory<Base>::DerivedRegister<TDerived> m_Reg;
};

template<class TDerived>
Factory<Base>::DerivedRegister<TDerived> BaseReg<TDerived>::m_Reg;

class Derived :
    public BaseReg<Derived>
{
};
类库:
公共工厂
{
};
模板
BaseReg类:
公共基地
{
静态工厂::派生寄存器m_Reg;
};
模板
Factory::DerivedRegister BaseReg::m_Reg;
派生类:
公共BaseReg
{
};
当我运行程序并尝试创建派生类的实例时,它在工厂中不存在,经过一点涂鸦后,我发现静态DerivedRegister从未在派生中构造,就像在构造函数中从未调用一样。我觉得这很奇怪。如果派生类不是模板,怎么能不强制静态初始化呢?当我制作一个虚拟静态对象,如下图所示,并在其静态构造中使用来自m_Reg的方法时,DerivedRegister突然正确构造,工厂可以实例化它,不费吹灰之力

class Base :
    public Factory<Base>
{
};

template<class TDerived>
class BaseReg :
    public Base
{
protected:
    static Factory<Base>::DerivedRegister<TDerived> m_Reg;
};

template<class TDerived>
Factory<Base>::DerivedRegister<TDerived> BaseReg<TDerived>::m_Reg;

class Derived :
    public BaseReg<Derived>
{
    class RandomClass
    {
    public:
         RandomClass(std::string meh) {}
    };

private:
    static RandomClass m_Obj;
};

Derived::RandomClass Derived::m_Obj(m_Reg.func());
类库:
公共工厂
{
};
模板
BaseReg类:
公共基地
{
受保护的:
静态工厂::派生寄存器m_Reg;
};
模板
Factory::DerivedRegister BaseReg::m_Reg;
派生类:
公共BaseReg
{
类随机类
{
公众:
随机类(std::string meh){}
};
私人:
静态随机类m_Obj;
};
派生::随机类派生::m_Obj(m_Reg.func());
那么,关于这个模板类的静态成员初始化,我没有得到什么?它不需要像任何其他非模板对象一样静态初始化对象吗

编辑:mkay,为了给大家一点启示,我将发布工厂对象。小心文字的墙。忽略额外的include、多余的GetNames和func函数,它们只是伏都教代码

#ifndef FACTORY_H
#define FACTORY_H

// library tools
#include <map>
#include <string>
#include <typeinfo>
#include <cstdlib>
#include <vector>
#include <iostream>
#include <cxxabi.h>

const std::string demangle(const char* name);

template<class base>
class Factory
{
protected:
    template<class T>
    static base * createT() { return new T;}

    typedef std::map<std::string, base*(*)()> map_type;

    static map_type& GetMap()
    {
        static map_type map;
        return map;
    }

public:
    virtual ~Factory(){}

    static base * createInstance(const std::string & s)
    {
        if(!GetMap().count(s))
            return nullptr;
        typename map_type::iterator it = GetMap().find(s);
        return it->second();
    }

    template <class TDerived>
    struct DerivedRegister :
        public Factory<base>
    {
        DerivedRegister()
        {
            std::string name = demangle(typeid(TDerived).name());
            GetMap().insert(std::pair<std::string, base*(*)()>(name, &createT<TDerived>));
        }

        DerivedRegister(const std::string& name)
        {
            GetMap().insert(std::pair<std::string, base*(*)()>(name, &createT<TDerived>));
        }

        std::string func() {return "meh";}
    };

    static void GetNames(std::vector<std::string>& names)
    {
        names.clear();

        for(auto it = GetMap().begin(); it != GetMap().end(); ++it)
            names.push_back(it->first);

    }
};


#endif
\ifndef工厂
#定义工厂
//图书馆工具
#包括
#包括
#包括
#包括
#包括
#包括
#包括
常量std::字符串demangle(常量字符*名称);
模板
阶级工厂
{
受保护的:
模板
静态基*createT(){return new T;}
typedef std::map映射类型;
静态映射类型&GetMap()
{
静态地图\ U型地图;
返回图;
}
公众:
虚拟~Factory(){}
静态基*createInstance(常量std::string&s)
{
如果(!GetMap().count)
返回空ptr;
typename map_type::迭代器it=GetMap().find;
返回它->秒();
}
模板
结构派生寄存器:
公共工厂
{
派生寄存器()
{
std::string name=demangle(typeid(TDerived).name());
GetMap().insert(std::pair(name,&createT));
}
DerivedRegister(常量标准::字符串和名称)
{
GetMap().insert(std::pair(name,&createT));
}
std::string func(){返回“meh”;}
};
静态void GetNames(std::vector和names)
{
name.clear();
对于(自动it=GetMap().begin();it!=GetMap().end();++it)
名称。推回(it->first);
}
};
#恩迪夫

假设工厂本身是静态构造的,或者工厂是作为其他静态构造链的一部分构造的,那么您可能会遇到无法预测的静态初始化顺序的麻烦

您可以通过包装并在其自身函数中使用static来解决此问题:

template<class TDerived>
class BaseReg :
    public Base
{
protected:
    static Factory<Base>::DerivedRegister<TDerived> & Reg()
    {
        static Factory<Base>::DerivedRegister<TDerived> m_Reg;
        return m_Reg;
    }
};
模板
BaseReg类:
公共基地
{
受保护的:
静态工厂::DerivedRegister&Reg()
{
静态工厂::派生寄存器m_Reg;
返回m_Reg;
}
};
现在,访问
m_Reg
的唯一方法是调用
Reg()
,然后您可以确定
m_Reg
已构建。也就是说,它是在第一次使用时构建的


我已经成功地用上述方法修复了一些非常棘手的问题,现在我理所当然地使用它,以避免调试奇怪的崩溃。我几乎再也不需要静态成员变量了。

这与我用来确保在需要时初始化factory对象中的stl映射的方法完全相同。问题是,我从不使用m_Reg。它唯一的用途就是它的构造函数。它的构造函数将在工厂中调用GetMap,以确保它是以前生成的,所以我真正需要的是确保构造函数执行。我在DerivedRegister构造函数中放置了一个小的伪打印输出,两个构造函数都没有被调用。这可能是某种编译器优化吗?(添加了Factory.h顺便说一句,太少了,无法继续:\)