[英]Constructing a compile-time list of templated types?
對不起,措辭含糊。 我遇到了一個似乎應該可以解決的問題,但是我的調查陷入了死胡同。 簡而言之,我想要一個編譯時列表,其中包含所有從類A繼承的類型。如此說來,我將直接進入我所面臨的問題。
說我有兩種類型:實體和組件。
class Entity {
public:
entity_id id;
std::vector<component_id> components;
};
和
template<typename UnderlyingComponentType>
class Component {
public:
static std::vector<UnderlyingComponentType> components;
component_id id;
entity_id containingEntity;
}
簡而言之,每個實體都包含多個具有不同類型的組件(例如,TextComponent,SoundComponent,WeightComponent)。 但是,不是直接將這些組件包含為字段,而是將它們的ID存儲在實體中。 這允許在相同類型的組件上進行快速迭代,因為它們都在一個連續的向量中(例如,所有DescriptionComponent都可以一次性遍歷)。 同樣,可以為任何給定實體檢索給定類型的任何Component:
DescriptionComponent& decription = myEntity.getComponent<DescriptionComponent>()
// Can go to the DescriptionComponent's static vector, and look up the
// appropriate component given our entity's ID (matching it with the component's
// containingEntity ID.)
可以提供類似的功能來刪除單個組件或添加組件。 但是,當我想刪除給定實體的所有組件時,我遇到了一個問題。 因為組件存儲在實體外部,所以沒有一種簡單的方式說“循環遍歷您包含的組件並將其全部刪除”。 相反,我們必須轉到包含的每種組件類型的基礎靜態向量,然后從那里刪除。 這是我碰到磚牆的地方。 似乎這里有兩個潛在的解決方案:
1.)在每個實體中存儲類型集合,這些類型映射到我們包含的所有組件類型的組件向量(例如, entity.getComponentTypes == X<DescriptionComponent, SoundComponent>;
這里的缺點是每個實體的組件可以始終為變化(我可以在上面的示例中在運行時添加一個WeightComponent
)。因此,我不相信有一種方法可以基於運行時類型信息(例如type_index
es等)鏈接到編譯時類型
2)生成,其實現了一種組件,然后依次通過他們都當實體要求刪除其所有組件的每一個類型的編譯時間列表。 例如,假設我們有一個實體e
,它的ID為123
,其中包含DescriptionComponent
和SoundComponent
。 我們仍然會有一個包含[DescriptionComponent, SoundComponent, WeightComponent]
的類型的編譯時列表,並且我們將告訴這些Component的每個靜態向量刪除123
引用的任何組件。 由於只有DescriptionComponent
和SoundComponent
向量具有這些引用,因此只有這兩個將刪除Components,並且e
所有分量都將被刪除。
上面的選項2似乎是更可行的選項:創建類型的編譯時列表。 手動編碼很容易: std::tuple<DescriptionComponent, SoundComponent, WeightComponent>
可以輕松存儲並允許我根據需要遍歷這些類型。 但是,理想情況下,我希望以編程方式生成此列表,因此,如果以后再添加NameComponent
,則無需更新其他任何代碼:從我的繼承繼承時應自動對其進行管理模板化的Component
類。 例如,
class NameComponent : public Component<NameComponent> {
//implementation details
}
//Now, my all-types list should contain [DescriptionComponent, SoundComponent,
// WeightComponent, NameComponent], and I didn't have to update any config.
我完全不確定上述方法是否可以在本地實現,但是任何幫助或資源建議都是可行的。 我在這個StackOverflow問題上看到了類似的問題,但是它依賴於宏(據我所知,不要以相同的方式與模板進行交互)。 同樣,如果看起來這是一個A / B問題,並且像type_index
映射這樣的簡單解決方案實際上可以工作,那么這種批評也將受到歡迎! 我確定我已經忽略了一些細節或措辭不佳,請隨時告訴我是否/何時需要更多信息。
您可以使用類型擦除並存儲知道要處理的組件類型的元素,而不是在實體的向量中存儲component_id
。
#include <memory>
struct component_id{};
struct component_type_ref
{
template <typename Comp>
component_type_ref()
: _id(Comp::id), _impl(std::make_shared<_impl_t<Comp>>())
{
}
component_id id() const
{
return _id;
}
void clear()
{
_impl->clear();
}
private:
struct _impl_base
{
virtual void clear();
};
template <typename Comp>
struct _impl_t : public _impl_base
{
void clear()
{
Comp::components.clear();
}
};
component_id _id;
std::shared_ptr<_impl_base> _impl;
};
另請參閱https://channel9.msdn.com/Events/GoingNative/2013/Inheritance-Is-The-Base-Class-of-Evil
例如,通過這種方式,您可以在實體的向量中查找組件ID,然后對其進行調用clear。 因此,如果有要在組件類型上運行的已知操作列表(並且這些操作不必是模板),則可能是一種解決方案。
如果不是這種情況,那么恐怕您將需要使用類型向量。 這里不需要使用元組,簡單
template<typename... T> struct my_type_vector{};
可能就足夠了。 但是,正如您自己寫的那樣,在運行時這不太可行。
您可以使用以下方法制作類似於std::type_index
:
template<typename T>
void type_id() {}
using type_id_t = void(*)();
現在在您的地圖中,使用以下命令:
std::map<type_id_t, /* whatever */> myMap;
並像這樣檢索:
auto myElement = myMap[type_id</* somthing else */>];
這將在沒有RTTI的情況下完成工作
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.