如何解决模板函数引起的循环依赖?
例如,我定义了一个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类。我很难看到如何使用模板函数完成同样的工作。
答案 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
派生并专门/添加需要专门/添加的内容。