C++11多轨动画系统:同类型重复轨道静态存储问题
C++11多轨动画系统同类型轨道区分问题及解决
我正尝试仅使用C++11构建一个灵活的多轨动画系统,目前编写了如下代码:
#include <vector> #include <array> #include <unordered_map> #include <map> template<typename T> struct AnimationTrack { using map_type = std::map<float, T>; map_type keyframes; AnimationTrack(std::initializer_list<typename map_type::value_type>&& keyframes) : keyframes(std::move(keyframes)) {} }; template<typename T> struct AnimationTrackView { AnimationTrack<T>* track; AnimationTrackView() : track(nullptr) {} AnimationTrackView(AnimationTrack<T>* track) : track(track) {} }; template<typename... TrackTs> class Animation { public: Animation(AnimationTrack<TrackTs>&... tracks) { StoreViews(tracks...); } template<std::size_t Index> auto& GetTrack() { return GetStorage<std::tuple_element<Index, std::tuple<TrackTs...>>::type>()[this].track; } private: template<typename T> static auto& GetStorage() { static std::unordered_map<Animation*, AnimationTrackView<T>> storage; return storage; } template<typename T, typename... Ts> void StoreViews(AnimationTrack<T>& current, AnimationTrack<Ts>&... rest) { auto& storage = GetStorage<T>(); storage.emplace(this, std::addressof(current)); using expander = int[]; (void)expander { 0, (void(GetStorage<Ts>().emplace(this, std::addressof(rest))), 0)... }; } }; int main() { AnimationTrack<float> test1( { { 0.2f, 1.0f }, { 0.5f, 2.0f }, { 0.9f, 3.0f } }); AnimationTrack<int> test2( { { 0.2f, 1 }, { 0.5f, 2 }, { 0.9f, 3 } }); Animation<float, int> anim(test1, test2); auto track0 = anim.GetTrack<0>(); auto track1 = anim.GetTrack<1>(); }
该实现在不同类型轨道的场景下运行正常,但当需要创建两条同类型的轨道时,调用GetTrack方法会导致两条轨道共用同一静态存储,无法正确区分。
解决方案
已找到可行的解决思路,修改后的代码如下:
#include <iostream> #include <vector> #include <array> #include <unordered_map> #include <map> // Helper functions because C++11 doesn't have integer_sequence namespace details { template<typename T, T... Ints> struct integer_sequence { typedef T value_type; static constexpr std::size_t size() { return sizeof...(Ints); } }; template<std::size_t... Ints> using index_sequence = integer_sequence<std::size_t, Ints...>; template<typename T, std::size_t N, T... Is> struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Is...> {}; template<typename T, T... Is> struct make_integer_sequence<T, 0, Is...> : integer_sequence<T, Is...> {}; template<std::size_t N> using make_index_sequence = make_integer_sequence<std::size_t, N>; template<typename... T> using index_sequence_for = make_index_sequence<sizeof...(T)>; } template<typename T> struct AnimationTrack { using map_type = std::map<float, T>; map_type keyframes; AnimationTrack(std::initializer_list<typename map_type::value_type>&& keyframes) : keyframes(std::move(keyframes)){} }; template<typename T> struct AnimationTrackView { AnimationTrack<T>* track; AnimationTrackView() : track(nullptr) {} AnimationTrackView(AnimationTrack<T>* track) : track(track) {} }; template<typename... TrackTs> class Animation { public: Animation(AnimationTrack<TrackTs>&... tracks) { StoreViews(details::make_index_sequence<sizeof...(TrackTs)>(), tracks...); } template<std::size_t Index> auto& GetTrack() { auto storage = GetStorage<std::tuple_element<Index, std::tuple<TrackTs...>>::type, Index>(); return *storage[this].track; } private: template<typename T, std::size_t Index> static auto& GetStorage() { static std::unordered_map<Animation*, AnimationTrackView<T>> storage; return storage; } template<std::size_t... Indices, typename... Ts> void StoreViews(details::index_sequence<Indices...> sequence, AnimationTrack<Ts>&... rest) { using expander = int[]; (void)expander { 0, (void(GetStorage<Ts, Indices>().emplace(this, std::addressof(rest))), 0)... }; } }; int main() { AnimationTrack<float> test1( { { 0.2f, 1.0f }, { 0.5f, 2.0f }, { 0.9f, 3.0f } }); AnimationTrack<float> test2( { { 0.2f, 9.0f }, { 0.5f, 8.0f }, { 0.9f, 7.0f } }); Animation<float, float> anim(test1, test2); auto track0 = anim.GetTrack<0>(); auto track1 = anim.GetTrack<1>(); }
内容的提问来源于stack exchange,提问作者Alexandre Deus
相关产品推荐
相关产品推荐

