我试图在C ++中实现一个通用的ECS库用于学习目的。我正在考虑很多实现方法,但我总是遇到问题。所以,如果你能帮助我解决这个问题:
假设我有constexpr hana::tuple
hana::type_c
个组件,例如:
struct C1 {};
struct C2 {};
struct C3 {};
constexpr auto components = hana::to_tuple(hana::tuple_t<C1, C2, C3>);
现在我有一个组件存储类型,这在这里不是问题,所以我们称之为存储(每个组件的类型不同):
struct Storage {};
我想将每个组件或每个组件组与其Storage
类型相关联。所以简单的方法就是这样做:
constexpr auto component_storage = hana::make_tuple(
hana::make_pair(hana::to_tuple(hana::tuple_t<C1, C2>), type_c<Storage>),
hana::make_pair(hana::to_tuple(hana::tuple_t<C3>), type_c<Storage>)
);
但问题现在是运行时。如果我使用真实存储而不是type_c<Storage>
来初始化该元组,我将不得不遍历元组以找到我需要的Storage
。所有这些在运行时没有?
这真的很糟糕,我的上一个版本有Component::getStorage()
这样的东西,它是免费的(但限制性更强)。
所以问题是:我怎样才能设置一些getStorage<Component>()
函数,它在运行时不需要任何费用?我什么都没有意思只是返回存储的引用。
编辑:到目前为止,我想到的唯一方法很简单(听起来很不错)。
伪代码
struct LinkedStorage {
hana::tuple<...> storages;
hana::tuple<hana::pair...> index;
};
至少可以这样:
constexpr auto components = hana::to_tuple(hana::tuple_t<C1, C2, C3>);
constexpr auto storage = hana::to_tuple(hana::tuple_t<Storage, Storage>);
constexpr auto index = hana::make_tuple(
hana::make_pair(hana::to_tuple(hana::tuple_t<C1>, 0),
hana::make_pair(hana::to_tuple(hana::tuple_t<C2, C3>, 1)
);
就像我应该能够在编译时找到索引并在运行时访问正确的元素。但我是元编程的新手,所以我猜有人可以做得更好。
答案 0 :(得分:2)
首先,不需要使用car1: 2
car2: 3
truck: 1
bike: 2
;你可以使用var r = jQuery.grep(arr, function(a) {
return a.indexOf('car') === 0;
});
。现在,我认为你真正想做的事情(因为你似乎需要运行时存储,这是有道理的)是:
to_tuple(tuple_t<...>)
现在,您可以像这样实施tuple_t<...>
功能:
// "map" of a set of types to a storage of some type
using StorageMap = hana::tuple<
hana::pair<hana::tuple<hana::type<C1>, hana::type<C2>>, StorageA>,
hana::pair<hana::tuple<hana::type<C3>>, StorageB>
>;
// Actual object that contains the runtime storage (and the free mapping between types)
StorageMap map;
其中getStorage<Component>()
是函数in this answer的一个简单变体,它可以处理任意谓词而不是特定元素。当我获得空闲时间时,此功能将添加到Hana(请参阅related ticket)。
答案 1 :(得分:1)
看起来您正在尝试制作可以使用不同键查找单个实例的地图。这是我写的旧实现的片段。我修改了一下,但它应该传达这个想法。
namespace detail {
// extractKeys - returns pairs of each element and itself
struct extract_keys_fn
{
template<typename TypesType>
constexpr auto operator()(TypesType s) const {
return decltype(hana::unpack(typename TypesType::type{},
hana::make_tuple
^hana::on^
hana::reverse_partial(hana::make_pair, s)
)){};
}
};
constexpr extract_keys_fn extract_keys{};
}//detail
template<typename ...Pair>
struct multi_map
{
// the keys must be `type<tuple<path...>>`
using Storage = decltype(hana::make_map(std::declval<Pair>()...));
// each key is a hana::tuple which contain the keys we
// want to use to lookup an element
using Lookup = decltype(hana::unpack(
hana::flatten(hana::unpack(hana::keys(std::declval<Storage>()),
hana::make_tuple ^hana::on^ detail::extract_keys)),
hana::make_map
));
constexpr multi_map()
: storage()
{ }
constexpr multi_map(Pair&&... p)
: storage(hana::make_map(std::forward<Pair>(p)...))
{ }
constexpr multi_map(Pair const&... p)
: storage(hana::make_map(p...))
{ }
constexpr multi_map(Pair&... p)
: storage(hana::make_map(p...))
{ }
template<typename T>
constexpr decltype(auto) operator[](T t) const&
{
return hana::at_key(storage, hana::at_key(Lookup{}, t));
}
template<typename T>
constexpr decltype(auto) operator[](T t) &
{
return hana::at_key(storage, hana::at_key(Lookup{}, t));
}
template<typename T>
constexpr decltype(auto) operator[](T t) &&
{
return hana::at_key(storage, hana::at_key(Lookup{}, t));
}
Storage storage;
};
上面发生的事情的基础是storage
是一个hana::map
,其中包含您需要引用的实例。然后Lookup
是hana::map
,它将每个键指向storage
中使用的键(这是指向它的所有键的元组)。它基本上只是一个映射的地图,但有了它,您可以使用任何一个键获得对单个实例的引用。