I'm writing an interpreter for a scripting language which allows objects to:Have an aliasBe referenced using a wildcardContain child objectsCombination of all three aboveFor example:CreateWindow(win, ...);CreateName(win/texes1, ...);CreateName(win/texes2, ...);CreateAlias(win/texes1, wintexes);CreateAlias(win/texes2, wintexes2);CreateTexture(@wintexes/tex1, ...);CreateTexture(@wintexes/tex2, ...);Delete(@wintexes/*); // Deletes texturesDelete(@wintexes*); // Deletes namesDelete(win);Crazy, I know. It wasn't me who came up with it though.In order to call the function on all objects intended to be affected by it, I came up with this code:class ObjectHolder_t : private Holder<Object>{public:    virtual ~ObjectHolder_t()    {    }    Object* Read(const string& Handle)    {        string Leftover = Handle;        string ObjHandle = ExtractObjHandle(Leftover);        if (Leftover.empty())            return Holder::Read(ObjHandle);        return GetHolder(ObjHandle)->Read(Leftover);    }    void Write(const string& Handle, Object* pObject)    {        string Leftover = Handle;        string ObjHandle = ExtractObjHandle(Leftover);        if (Leftover.empty())            Holder::Write(ObjHandle, pObject);        else            GetHolder(ObjHandle)->Write(Leftover, pObject);    }    template <class F>    void Execute(const string& Handle, F Func)    {        string Leftover = Handle;        string ObjHandle = ExtractObjHandle(Leftover);        if (ObjHandle.back() == '*')            ObjHandle.front() == '@' ? WildcardAlias(Leftover, ObjHandle, Func) : WildcardCache(Leftover, ObjHandle, Func);        else            Leftover.empty() ? Func(&Cache.find(ObjHandle)->second) : GetHolder(ObjHandle)->Execute(Leftover, Func);    }    void WriteAlias(const string& Handle, const string& Alias)    {        Aliases[Alias] = Handle;    }private:    template <class F>    void ExecuteSafe(const string& HolderHandle, const string& Handle, F Func)    {        if (ObjectHolder_t* pHolder = GetHolder(HolderHandle))            pHolder->Execute(Handle, Func);    }    template <class F>    void WildcardAlias(const string& Leftover, const string& ObjHandle, F Func)    {        std::regex Regex(Regexify(ObjHandle.substr(1)));        for (auto i = Aliases.begin(); i != Aliases.end(); ++i)            if (std::regex_match(i->first, Regex))                Leftover.empty() ? Execute(i->second, Func) : ExecuteSafe(i->second, Leftover, Func);    }    template <class F>    void WildcardCache(const string& Leftover, const string& ObjHandle, F Func)    {        std::regex Regex(Regexify(ObjHandle));        for (auto i = Cache.begin(); i != Cache.end(); ++i)            if (std::regex_match(i->first, Regex))                Leftover.empty() ? Func(&i->second) : ExecuteSafe(i->first, Leftover, Func);    }    string Regexify(const string& Wildcard)    {        return string(^ + Wildcard.substr(0, Wildcard.size() - 1) + .*);    }    string ExtractObjHandle(string& Handle)    {        // Name        string ObjHandle;        size_t Index = Handle.find('/');        if (Index != string::npos)        {            ObjHandle = Handle.substr(0, Index);            Handle = Handle.substr(Index + 1);        }        else        {            ObjHandle = Handle;            Handle.clear();        }        // Alias        if (ObjHandle.front() == '@' && ObjHandle.back() != '*')        {            Handle = Aliases[ObjHandle.substr(1)] + / + Handle;            ObjHandle = ExtractObjHandle(Handle);        }        return ObjHandle;    }    ObjectHolder_t* GetHolder(const string& Handle)    {        return (ObjectHolder_t*)(Holder::Read(Handle));    }    map<string, string> Aliases;};Variable name Cache is a bit misleading here, but that's what I get for reusing Holder<T> which was intended for another purpose. Cache is actually std::map<std::string, Object*>.struct MapDeleter{    template <class T> void operator() (T Data) { delete Data.second; }};template <class T>struct Holder{    ~Holder()    {        for_each(Cache.begin(), Cache.end(), MapDeleter());    }    T* Read(const string& Path)    {        auto iter = Cache.find(Path);        if (iter != Cache.end())            return iter->second;        return nullptr;    }    void Write(const string& Path, T* Data)    {        Cache[Path] = Data;    }    map<string, T*> Cache;};The code is used like this:void NSBInterpreter::Move(){    string Handle = PopString();    int32_t Time = PopInt();    int32_t X = PopInt();    int32_t Y = PopInt();    /*int32_t Tempo = */PopInt();    bool Wait = PopBool();    ObjectHolder.Execute(Handle, [Time, X, Y] (Object** ppObject)    {        if (Texture* pTexture = dynamic_cast<Texture*>(*ppObject))            pTexture->Move(Time, X, Y);    });    if (Wait)        pContext->Wait(Time);}My concern with this code is that it is very complex and spaghetti recursive (although recursion isn't very deep so it won't crash) and I will probably forget how exactly it works by the time it needs fixing. Any thoughts on improving this?
Object storing and retrieving using wildcard identifier
c++;c++11;recursion;template;stl
This is an answer-length response to Mislav's comment, which asked two questions.I'm not sure how is (13) supposed to work. One way would be to construct a list of objects and return it, but I guess that's not very efficient.To be able to writefor (Object *pObject : ObjectHolder.Write(Handle)) {   ...}we need to make ObjectHolder_t::Write() return an object with begin() and end() methods, which when called return iterator objects (implementing operator* and operator++) that do the right thing in context. That is, something like#include <string>#include <map>#include <memory>#include <regex>#include <type_traits>template<class Iter>struct IterPair {    Iter b_, e_;    IterPair(Iter b, Iter e): b_(std::move(b)), e_(std::move(e)) {}    Iter begin() const { return b_; }    Iter end() const { return e_; }};template<class T>struct Holder {    using ptr_t = std::unique_ptr<T>;    using cache_t = std::map<std::string, ptr_t>;    cache_t cache_;    template<bool WritingAllowed>    class Iterator {        using star_t = typename std::conditional<WritingAllowed, ptr_t, const ptr_t>::type;        using ctor_t = typename std::conditional<WritingAllowed, cache_t, const cache_t>::type;        using cur_t = typename std::conditional<WritingAllowed, typename cache_t::iterator, typename cache_t::const_iterator>::type;        friend class Holder<T>;        cur_t cur_, end_;        std::regex rx_;        explicit Iterator(ctor_t& map) : cur_(map.end()), end_(map.end()) {}        explicit Iterator(ctor_t& map, std::regex rx) : cur_(map.begin()), end_(map.end()), rx_(std::move(rx)) {            while (cur_ != end_ && !std::regex_match(cur_->first, rx_)) {                ++cur_;            }        }    public:        star_t& operator*() const {            return cur_->second;        }        Iterator& operator++() {            do {                ++cur_;            } while (cur_ != end_ && !std::regex_match(cur_->first, rx_));            return *this;        }        bool operator==(const Iterator& rhs) const { return cur_ == rhs.cur_; }        bool operator!=(const Iterator& rhs) const { return cur_ != rhs.cur_; }    };    // for pedagogical purposes only    Holder() {        cache_.insert(std::make_pair(alpha, std::make_unique<int>(1)));        cache_.insert(std::make_pair(beta, std::make_unique<int>(2)));        cache_.insert(std::make_pair(gamma, std::make_unique<int>(3)));        cache_.insert(std::make_pair(delta, std::make_unique<int>(4)));    }    IterPair<Iterator<false>> Read(const std::regex& path_regex) const {        using Iter = Iterator<false>;        return { Iter(cache_, path_regex), Iter(cache_) };    }    IterPair<Iterator<true>> Write(const std::regex& path_regex) {        using Iter = Iterator<true>;        return { Iter(cache_, path_regex), Iter(cache_) };    }};#include <stdio.h>int main(){    Holder<int> h;    for (const std::unique_ptr<int>& pi : h.Read(std::regex(.*ta))) {        printf(%d\n, *pi);    }}Remove the const in main() to see what kind of compiler error you get if you try to write to the result of a Read() call.Another problem is that one specific Func is supposed to be able to delete the object...I think you'll find that the iterator design removes this problem entirely:void NSBInterpreter::Delete() {    std::string Handle = PopString();    for (std::unique_ptr<Object>& pObj : ObjectHolder.Write(Handle)) {        if (NSBContext* pThread = dynamic_cast<NSBContext*>(pObj.get())) {            RemoveThread(pThread);        }        pObj = nullptr;    }}However, using your original visitor design, I would observe that the operation delete this object needs to be managed by the ObjectHolder itself, and therefore I would tend to implement the operation via a manager object passed in to the visitor function.void NSBInterpreter::Delete() {    std::string Handle = PopString();    ObjectHolder.Execute(Handle, [this](Object** ppObject, ObjectHolder_t::Manager& mgr) {        if (NSBContext* pThread = dynamic_cast<NSBContext*>(*ppObject)) {            RemoveThread(pThread);        }        mgr.Delete(ppObject);  // or perhaps just mgr.DeleteCurrentObject();    });}