C ++模板函数导致循环依赖

时间:2015-02-16 13:18:20

标签: c++ templates circular-dependency entity-system

如何解决模板函数引起的循环依赖?

例如,我定义了一个Engine类,它存储了一个实体列表,并负责创建实体并从中添加/删除组件。

class Engine
{
public:
    Entity CreateEntity();

    template <typename T, typename... Args>
    void AddComponentToEntity(Entity& entity, Args... args)
    {
        // Code to add component to entity
    }

    template <typename T>
    void RemoveComponentFromEntity(Entity& entity)
    {
        // Code to remove component from entity
    }

private:
    std::vector<Entity> entities;
};

我还在实体类中添加了函数&#34; wrap&#34;这些函数允许一个很好的语法来向实体添加组件。

class Entity
{
public:

    template <typename T, typename... Args>
    void AddComponent(Args... args)
    {
        engine->AddComponentToEntity<T>(*this, args...);
    }

    template <typename T>
    void RemoveComponent()
    {
        engine->RemoveComponentFromEntity<T>(*this);
    }

private:
    Engine* engine;
};

这允许我编写像这样的代码

entity.AddComponent<PhysicsComponent>(Arguments..);

而不是必须直接引用引擎对象

engine->AddComponentToEntity(entity, Arguments..);

但是,由于引擎类包含实体实例,因此必须包含Entity类。然后,Entity类必须包含Engine类,以便模板函数调用方法,这会导致循环依赖。

如果函数不是模板,这很容易解决,因为实现可以放在Entity.cpp中,然后我可以在那里包含Engine类。我很难看到如何使用模板函数完成同样的工作。

3 个答案:

答案 0 :(得分:0)

你可以通过从声明中分割定义来完成,就好像函数不是模板一样:

// Engine.h

#ifndef ENGINE_H
#define ENGINE_H

#include <vector>
class Entity; // forward declaration

class Engine
{
public:
    Entity CreateEntity();

    template <typename T, typename... Args>
    void AddComponentToEntity(Entity& entity, Args... args);

    template <typename T>
    void RemoveComponentFromEntity(Entity& entity);

private:
    std::vector<Entity> entities;
};

#include "engine.inl"

#endif

// Engine.inl

#ifndef ENGINE_INL
#define ENGINE_INL

#include "engine.h"
#include "entity.h"

template <typename T, typename... Args>
void Engine::AddComponentToEntity(Entity& entity, Args... args)
{
    // Implementation.
}

template <typename T>
void Engine::RemoveComponentFromEntity(Entity& entity)
{
    // Implementation.
}

#endif

类似于 entity.h / entity.inl

答案 1 :(得分:0)

您可以先写入类定义,然后再编写函数实现来解决它。例如:

class Engine;
class Entity
{
public:

    template <typename T, typename... Args>
    void AddComponent(Args... args);

    template <typename T>
    void RemoveComponent();

private:
    Engine* engine;
};

class Engine
{
public:
    Entity CreateEntity();

    template <typename T, typename... Args>
    void AddComponentToEntity(Entity& entity, Args... args);

    template <typename T>
    void RemoveComponentFromEntity(Entity& entity);

private:
    std::vector<Entity> entities;
};

template <typename T, typename... Args>
void Entity::AddComponent(Args... args)
{
        engine->AddComponentToEntity<T>(*this, args...);
}

template <typename T>
void Entity::RemoveComponent()
{
        engine->RemoveComponentFromEntity<T>(*this);
}

void Engine::AddComponentToEntity(Entity& entity, Args... args)
{
        // Code to add component to entity
}

template <typename T>
void Engine::RemoveComponentFromEntity(Entity& entity)
{
        // Code to remove component from entity
}

这样您就不必拆分文件了。

答案 2 :(得分:0)

这里的主要问题是您的课程设计。 engine包含的entity带有向entity添加组件的责任,这是毫无意义的。

如果您在添加组件时有不同的行为,则根据引擎,您可以使引擎成为Entity::AddComponent函数的参数:

template <typename Engine, typename T, typename... Args>
void AddComponent(Engine engine, Args... args)
{
    engine->AddComponentToEntity<T>(*this, args...);
}

另一方面,您可以使用成语Curiously recurring template pattern并将成员Engine::entities移至Entity::entities(或Entity::children,如果您尝试执行某种树数据结构)。

template <typename Entity>
class Engine
{
public:
    Engine(){}
    void addComponent(Entity entity, ...){}
}


class Entity: public Engine<Entity>
{
    // Now this class has the function addComponent
    // just like defined in Engine.
private:
    std::vector<Entity> children; // Here this has more sense.
};

如果您需要不同的引擎,只需从Engine派生并专门/添加需要专门/添加的内容。