所以我有这个我为c ++ 0X编写的c ++代码。它曾用于在MSVC 2012中编译,但现在我切换到MingW64 4.8.1,因为我对MSVC中缺少C ++ 11支持感到不满意。以下是一些实现简单实体/组件系统的代码的一部分。
这是我得到的错误:
if(e-> components.find(T :: ID)== e-> components.end())
未定义的引用 `EL :: Position3DComponent :: ID' ELEntityManager.h / Elementium / Elementium行 64 C / C ++问题
与使用T :: ID ...
有关以下是我在MSVC 2012中使用此代码的一些进一步说明:
在每个组件中,我都有一个静态const ELComponentID成员,它被初始化为组件的id。使用它是因为我需要轻松获取具有特定组件的实体,因此我在ELEntityManager中使用多重映射,其键是ELComponentID,其值是包含具有此类组件的ELEntity的unique_ptr。
在ELEntity类中,我使用了一个unordered_map,其键是ELComponentID,其值是包含所讨论的ELComponent的unique_ptr。
是的,它确实占用了更多的内存,但我主要是为了访问速度。
文件ELEntityManager.h:
//Includes
#include <map>
#include <memory>
#include "ELEntity.h"
#include "ELComponent.h"
namespace EL{
class ELEntityManager
{
public:
//...
template<typename T> void addComponent(std::unique_ptr<ELEntity> e, std::unique_ptr<ELComponent> c)
{
if(c == nullptr || e == nullptr)
return;
if(e->components.find(T::ID) == e->components.end()) //***** <-- This is where I get the error.
{
//...
}
//...
}
//...
private:
//******************************************
// Private data members
//******************************************
std::multimap<ELComponentID, std::unique_ptr<ELEntity> > entities;
};
};// End namespace
文件ELEntity.h:
//Includes
#include <unordered_map>
#include <memory>
#include "ELComponent.h"
namespace EL{
class ELEntity
{
friend class ELEntityManager;
//...
private:
//******************************************
// Private data members
//******************************************
/**The map of ComponentIDs with their components.*/
std::unordered_map<ELComponentID, std::unique_ptr<ELComponent> > components;
};
};// End namespace
文件ELComponent.h:
//Includes
#include <unordered_map>
#include <functional>
#include <string>
#include <vector>
#include "ELMath.h"
namespace EL{
/**
* Component IDs.
*/
enum ELComponentID {
LogicalDevice = 1, // Start the enum at 1.
Viewport,
Position3D,
Position2D,
Orientation,
PhysicsRK4
};
/**
* Base component class.
*/
struct ELComponent
{
};
/**
* Position3D component, derives from ELVector3D in EL::Math.
*/
struct Position3DComponent: public ELComponent, EL::Math::ELVector3D
{
static const ELComponentID ID = Position3D;
};
//...
然后我在main.cpp中将它作为测试(包含所有必需的包括等等):
EL::ELEntityManager em;
std::unique_ptr<EL::ELEntity> e(new EL::ELEntity());
std::unique_ptr<EL::Position3DComponent> obj(new EL::Position3DComponent());
obj->x = 1.0;
obj->y = 2.0;
obj->z = 3.0;
em.addComponent<EL::Position3DComponent>(std::move(e), std::move(obj));
现在我的问题是,我做错了什么是gcc特有的,gcc / mingw中不支持T :: ID,或者在最终的c ++ 11实现中没有任何改变对于MSVC 2012?
如何修复此错误?如果它不能在c ++ 11中完成,或者如果gcc中存在错误,我可以用其他任何方式执行此操作吗?
非常感谢您的回复! :)
答案 0 :(得分:0)
我认为海湾合作委员会是对的。从您发布的代码中,我觉得您没有为静态数据成员提供定义。
由于您将T::ID
输入传递给std::unordered_map::find()
,其参数通过引用,因此您使用ID
(ODR代表One)简而言之,规则和odr使用意味着编译器需要知道该对象的地址。)
由于需要静态数据成员的地址,但未提供全局命名空间的定义,因此最终会出现链接器中未解决的符号错误。
根据C ++ 11标准的第9.4.2 / 3段:
如果非易失性const静态数据成员是整数或枚举类型,则其在类中声明 定义可以指定大括号或等于初始值,其中每个 initializer-clause 是赋值表达式 是一个常量表达式(5.19)。 [...]仍然应该定义成员 如果在程序中使用odr-used(3.2)并且命名空间作用域定义不在,则在命名空间作用域中 包含初始化程序。
因此,要解决此问题,只需在.cpp
文件(或只有一个.cpp
文件包含的标题)中的命名空间范围添加定义:
const ELComponentID Position3DComponent::ID;