मैं एक सामान्य 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)
);
जैसे कि मुझे संकलित समय पर सूचकांक को खोजने में सक्षम होना चाहिए और रनटाइम पर सही तत्व तक पहुंचना चाहिए। लेकिन मैं मेटाप्रोग्रामिंग में नया हूं, इसलिए मुझे लगता है कि कोई व्यक्ति कुछ बेहतर बना सकता है।
उत्तर:
जवाब के लिए 2 № 1सबसे पहले, उपयोग करने की कोई आवश्यकता नहीं है 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>()
इस तरह काम करें:
template <typename Component>
decltype(auto) getStorage() {
auto found = index_if(map, [](auto const& pair) {
return hana::contains(hana::first(pair), hana::type<Component>{});
});
return hana::second(hana::at(map, found));
}
कहा पे index_if
प्रस्तुत समारोह का एक तुच्छ संस्करण है इस जवाब में कि एक विशिष्ट तत्व के बजाय एक मनमाना विधेय पर काम करेगा। जब मुझे कुछ खाली समय मिलेगा (तो देखें) यह कार्यक्षमता हाना में जोड़ दी जाएगी संबंधित टिकट)।
उत्तर № 2 के लिए 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
(सभी बिंदुओं की एक गुच्छी जो इसे इंगित करती है)। यह मूल रूप से नक्शे के लिए सिर्फ एक नक्शा है, लेकिन इसके साथ आप किसी भी एक कुंजी का उपयोग करके एकल उदाहरण का संदर्भ प्राप्त कर सकते हैं।