简体   繁体   English

C ++在模板中使用静态const类成员

[英]C++ using a static const class member in a template

So I have this c++ code which I have written for c++0X. 所以我有为c ++ 0X编写的这段c ++代码。 It used to compile in MSVC 2012, but now I switched to MingW64 4.8.1 because I was dissatisfied with the lack of C++11 support in MSVC. 它曾经在MSVC 2012中进行编译,但是现在我切换到MingW64 4.8.1,因为我对MSVC中缺少C ++ 11支持感到不满意。 The following is part of some code which implements a simple Entity/Component System. 以下是实现简单实体/组件系统的某些代码的一部分。

This is the error I get: 这是我得到的错误:

if(e->components.find(T::ID) == e->components.end()) if(e-> components.find(T :: ID)== e-> components.end())

undefined reference to `EL::Position3DComponent::ID' ELEntityManager.h /Elementium/Elementium line 64 C/C++ Problem 未定义对EL :: Position3DComponent :: ID的引用ELEntityManager.h / Elementium / Elementium第64行C / C ++问题

which is related to using T::ID... 这与使用T :: ID ...有关

Here is some further explanation of what I used to use this code for in MSVC 2012: 这是我以前在MSVC 2012中使用此代码的内容的一些进一步说明:

In every component, I have a static const ELComponentID member which is initialized to the component's id. 在每个组件中,我都有一个静态const ELComponentID成员,该成员已初始化为组件的ID。 This is used because I need to easily get the entities which have a certain component, so I'm using a multimap in the ELEntityManager whose key is ELComponentID and whose value is a unique_ptr containing the ELEntity who has such a component. 之所以使用它,是因为我需要轻松获取具有特定组件的实体,因此我在ELEntityManager中使用了一个多图,其键为ELComponentID,其值是unique_ptr,其中包含具有此类组件的ELEntity。

In the ELEntity class, I use an unordered_map whose key is ELComponentID and whose value is a unique_ptr containing the ELComponent in question. 在ELEntity类中,我使用一个unordered_map,其键为ELComponentID,其值为包含所讨论的ELComponent的unique_ptr。

Yes it does take up a little more memory, but I do this mainly for access speed. 是的,它确实占用了更多的内存,但是我这样做主要是为了提高访问速度。

file ELEntityManager.h: 文件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

file ELEntity.h: 文件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

file ELComponent.h: 文件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;
};

//...

then I have this in main.cpp as a test (with all the required includes, etc...): 然后在main.cpp中将其作为测试(包括所有必需的include等):

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

Now my question is, am I doing something wrong which is gcc specific, is the T::ID not supported in gcc/mingw, or has anything changed in the final c++11 implementation which wasn't in for MSVC 2012? 现在我的问题是,我是否在做某些特定于gcc的错误,g:cc / mingw不支持T :: ID,或者在最终的c ++ 11实现中发生了什么变化,而MSVC 2012并未实现?

How do I fix this error? 如何解决此错误? If it can't be done anymore in c++11, or if there's a bug in gcc, can I do this any other way? 如果在c ++ 11中无法再执行此操作,或者gcc中存在错误,我可以通过其他方式执行此操作吗?

Thanks a lot in advance for your replies! 提前非常感谢您的答复! :) :)

I think GCC is right. 我认为海湾合作委员会是正确的。 From the code you posted, it seems to me you are not providing a definition for your static data member. 从您发布的代码来看,在我看来您没有为静态数据成员提供定义

Since you are passing T::ID in input to std::unordered_map::find() , which takes its argument by reference , you are odr-using ID (ODR stands for One Definition Rule, and odr-using means, in short, that the compiler needs to know the address of that object). 由于将输入中的T::ID传递给std::unordered_map::find() ,该参数以引用的形式接受参数,因此 ,您使用的是odr使用ID (ODR代表一个定义规则,简而言之,odr使用意味着,表示编译器需要知道该对象的地址)。

Since the address of the static data member is needed, but no definition at global namespace is provided, you end up with an unresolved symbol error from the linker. 由于需要静态数据成员的地址,但是没有提供全局名称空间的定义,因此最终会导致链接器出现无法解析的符号错误。

Per paragraph 9.4.2/3 of the C++11 Standard: 根据C ++ 11标准的9.4.2 / 3段:

If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression (5.19). 如果非易失性const静态数据成员是整数或枚举类型,则其在类定义中的声明可以指定大括号或相等初始化器 ,其中每个作为赋值表达式的 初始化子句都是一个常量表达式(5.19 )。 [...] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer . [...] 如果在程序中使用了成员(3.2),则成员仍应在名称空间范围中定义,并且名称空间范围定义不应包含初始化程序

Therefore, to solve the problem, just add a definition at namespace scope in a .cpp file (or in a header included by just one .cpp file): 因此,要解决该问题,只需在.cpp文件(或仅一个.cpp文件包含的标头)的名称空间范围内添加定义:

const ELComponentID Position3DComponent::ID;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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