You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 19:46:15