0

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

例如,我定义了一个 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;
};

然后,我还在实体类中添加了函数来“包装”这些函数,从而为向实体添加组件提供了一种很好的语法。

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.cpp 中,然后我可以在其中包含 Engine 类。我正在努力了解如何使用模板函数完成相同的操作。

4

3 回答 3

0

您的主要问题是您的课程的设计。engine包含在其中entity添加组件的责任的携带是没有意义的entity

如果您在添加组件时有不同的行为,具体取决于 Engine,您可以将 Engine 作为Entity::AddComponent函数的参数:

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

另一方面,您可以使用成语Curiously recurring 模板模式并将成员移动Engine::entitiesEntity::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并专门/添加需要专门/添加的内容。

于 2015-02-16T14:00:15.900 回答
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
}

这样您就不必拆分文件。

于 2015-02-16T13:28:36.847 回答
0

通过将定义从声明中拆分出来,您可以做的大部分工作就像函数不是模板一样:

// 引擎.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

// 引擎.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

于 2015-02-16T13:27:10.923 回答