2014-10-02 56 views
1

上下文

我目前正在我自己的庫上加載自定義腳本內的c + +應用程序。 下面是用於說明它正在做什麼一些示例代碼:腳本庫和功能模板

  1. 腳本部分:

test.ctv

script 
{ 
    object player = access("player"); 
    player.posX = 1 + 2; 
    access("map").load("map.txt"); 
} 
  • C++部分:
  • test.cpp

    class Player : public Loadable{ 
    private: 
    friend class cTVScript::scriptExecutor; 
    primaryLoadable<int> posX; 
    stringLoadable name; 
    public: 
    Player() : Loadable(&posX, "posX", &name, "name"); 
    } 
    
    class Map : public Loadable{ 
    private: 
    friend class cTVScript::scriptExecutor; 
    std::string mapName; 
    
    public: 
    void load(std::string map) { 
        mapName = map; 
    } 
    Map() : Loadable(&load, "load") {} 
    } 
    
    int main() { 
    Player *p = new Player(); 
    Map *m = new Map(); 
    cTVScript::LoadScript("test.ctv"); 
    cTVScript::AddObject(p, "player"); 
    cTVScript::AddObject(m, "map"); 
    std::cout << player.posX.get() << std::endl; // for example purpose we just assume that posX are public 
    std::cout << player.mapName.get() << std::endl; // same for mapName 
    } 
    

    問題

    變量訪問並通過cTVScript::scriptExecutor使用相當簡單, 但我的主要問題是在別處:

    • 如何,在C++中,我可以保存和型動物調用方法/功能原型?
    • 編譯器的一些技巧可以使它更容易? (如知道的類型和參數號碼?)

    當前變通

    使用戶定義像AccessibleLoad子fonction:

    class Map{ 
    [...] 
    public: 
    void load(std::string map) { 
        mapName = map; 
    } 
    static void AccessibleLoad(cTVScript::CallingPack& pack) { 
        /* arguments */ 
        std::string map; 
        pack.loadArguments(map); // here the user ask for each arguments 
    
        /*calling object */ 
        Map* _this; 
        pack.loadCallingObject(_this); // and here he ask for the calling object 
    
        _this->load(map); 
    } 
    Map() : Loadable(&AccessibleLoad, "load") {} 
    } 
    

    所以!

    有沒有一個技巧或某種方式,我可以使它更容易在我的庫中使用函數/方法? (像編譯器構建這些功能呢?(不這麼認爲,但更好的問))

    編輯

    有消息!我有我自己的答案,我會發布它(但它有點長) (順便說一句,英語不是我的母語,所以如果我犯了一個錯誤,說我這樣,我會編輯)

    +0

    考慮使用現有的解決方案,如C++中的Tcl:http://en.wikipedia.org/wiki/C%2B%2B/Tcl ... – PiotrNycz 2014-10-02 11:12:34

    +0

    @PiodrNycz這實際上是一個很好的庫,我以前使用過..但我有點想創造我的! – CollioTV 2014-10-02 12:46:47

    回答

    0

    詳細信息通過在上下文

    一個論據更多的理解(如果一個想要重新使用我的解決方案),我將詳細介紹我正在做的事情:

    • 有頂級(只能通過cTVScript::Executor
    • 和低級別(可見(或幾乎)由用戶)

    頂層(或者非類型化的部分)

    /*                                  
    * Non-Typed Part                              
    */ 
    class Loadable{ 
    public: 
        virtual std::string getAsString() { return ""; } 
    }; 
    
    struct parametersPack{ 
    public: 
        Loadable* returnValue; 
        std::vector<Loadable*> arguments; 
    }; 
    

    低電平(或鍵入部分)

    class StringLoadable : public Loadable{ 
    private: 
        std::string value; 
    public: 
        StringLoadable(std::string _s) : value(_s) {} 
        virtual std::string getAsString() { return value; } 
        virtual std::string get() { return value; } 
        virtual std::string& getRef() { return value; } 
    }; 
    
    template<typename type> 
    class primaryLoadable : public Loadable{ 
    private: 
        type value; 
    public: 
        primaryLoadable(type _v) : value(_v) {} 
        virtual std::string getAsString() { return std::to_string(value); } 
        type get() {return value;} 
        type& getRef() {return value;} 
    }; 
    

    保存功能與非匹配原型

    家長函數類(對於stocki納克他們):

    class functionLoadable : public Loadable{ 
    public: 
        virtual void call(parametersPack& pack) = 0; 
    }; 
    

    和次功能(一個void返回和其他與類型化收益)

    /*                                  
    * Static Loadable Function                            
    */ 
    template <typename Return, typename... Arguments> 
    class StaticLoadableFunction : public functionLoadable{ 
    private: 
        Return (*fn)(Arguments...); 
    public: 
        Return calling(Arguments... args) { 
        Return value = fn(args...); 
        return (value); 
        } 
        virtual void call(parametersPack& pack) { 
        Unpacker::applyFunc(pack.arguments, fn); 
        } 
        StaticLoadableFunction(Return (*_fn)(Arguments...)) : fn(_fn){} 
    }; 
    
    template <typename... Arguments> 
    class StaticLoadableFunction<void, Arguments...> : public functionLoadable{ 
    private: 
        void (*fn)(Arguments...); 
    public: 
        void calling(Arguments... args) { 
        fn(args...); 
        } 
        virtual void call(parametersPack& pack) { 
        Unpacker::applyFunc(pack.arguments, fn); 
        } 
        StaticLoadableFunction(void (*_fn)(Arguments...)) : fn(_fn){} 
    }; 
    

    現在拆包

    首先我需要解壓我的工作arguments從我std::vector

    /*                                 
        * Unpacking all arguments                            
        */ 
        template<unsigned int N> 
        struct helper; 
    
        template<unsigned int N> 
        struct helper{ 
        template <typename ReturnType, typename... Arguments, typename ...final> 
        static ReturnType applyFunc(std::vector<Loadable*> parameters, ReturnType (*fn)(Arguments...), final&&... args) { 
         return (helper<N - 1>::applyFunc 
           (parameters, fn, 
           convertLoadableTo< typename parametersType<N - 1, Arguments...>::type > 
           ::transform(parameters[N-1]), 
           args...)); 
        } 
        }; 
    
        template<> 
        struct helper<0>{ 
        template <typename ReturnType, typename ...Arguments, typename ...final> 
        static ReturnType applyFunc(std::vector<Loadable*> parameters, ReturnType (*fn)(Arguments...), final&&... args) { 
         return (fn(args...)); 
        } 
        }; 
    
        template <typename ReturnType, typename ...Arguments> 
        ReturnType applyFunc(std::vector<Loadable*> args, ReturnType (*fn)(Arguments...)) { 
        return (helper<sizeof...(Arguments)>::applyFunc(args, fn)); 
        } 
    

    我知道要千牛流至極類型在每個遞歸:

    /*                                 
        * Getting Parameters type N in variadic Templates                      
        */ 
        template <int N, typename... T> 
        struct parametersType; 
    
        template <typename T0, typename... T> 
        struct parametersType<0, T0, T...> { 
        typedef T0 type; 
        }; 
        template <int N, typename T0, typename... T> 
        struct parametersType<N, T0, T...> { 
        typedef typename parametersType<N-1, T...>::type type; 
        }; 
    

    然後垂頭喪氣我Loadable*對象爲primaryLoadable <>或StringLoadable

    /*                                 
        * Treat For Each Type                             
        */ 
        template <typename arg> 
        struct convertLoadableTo; 
    
        template <typename arg> 
        struct convertLoadableTo{ // int, double...etc                      
        static arg transform(Loadable* l) { 
         primaryLoadable<arg>* _l = 
         dynamic_cast< primaryLoadable<arg>* >(l); 
         if (!_l) 
         throw; 
         return (_l->get()); 
        } 
        }; 
    
        template <typename arg> 
        struct convertLoadableTo<arg&>{ // int&, double&...etc                    
        static arg& transform(Loadable* l) { 
         primaryLoadable<arg>* _l = 
         dynamic_cast< primaryLoadable<arg>* >(l); 
         if (!_l) 
         throw; 
         return (_l->getRef()); 
        } 
        }; 
    
        template <> 
        struct convertLoadableTo<std::string>{ // int&, double&...etc                   
        static std::string transform(Loadable* l) { 
         StringLoadable* _l = 
         dynamic_cast< StringLoadable* >(l); 
         if (!_l) 
         throw; 
         return (_l->get()); 
        } 
        }; 
    
        template <> 
        struct convertLoadableTo<std::string&>{ // int&, double&...etc                  
        static std::string& transform(Loadable* l) { 
         StringLoadable* _l = 
         dynamic_cast< StringLoadable* >(l); 
         if (!_l) 
         throw; 
         return (_l->getRef()); 
        } 
        }; 
    

    這就是下場!

    如果你想知道更多的細節請麻省理工學院!

    1

    在做C++ - >你的腳本調用。這是C++ 11的方式

    您將需要某種形式的打包器,可以採取一種類型,並將其添加。

    class SomeClassYouCanCallAScriptFunction { 
        // the order of these templates matter or else 
        // the one bellow will not be able to find the one higher 
    
        template<class T, class... Args> 
        callFunction(string name){ 
         // run your code to call your scripted function 
         // arguments has the arguments array 
        } 
    
        template<class T, class... Args> 
        callFunction(string name, T var){ 
         // last one 
         // either this 
         arguments.pack<T>(var); 
         // or this 
         arguments.pack(to_string(var)); 
         // or the like 
         // now do the next one 
         callFunction(name); 
        } 
    
    
    
        template<class T, class... Args> 
        callFunction(string name, T var, Args... args){ 
         // either this 
         arguments.pack<T>(var); 
         // or this 
         arguments.pack(to_string(var)); 
         // or the like 
         // now do the next one 
         callFunction(name, args...); 
        } 
    
    
    
    
    
    
    
    } 
    
    
    someClass.callFunction("scriptFunc", "ya", 42, someVectMaybe); 
    

    圍繞你能做的最好的otherway是提供arguments變量,讓用戶獲得類似arguments.get<T>(index)

    +0

    你的答案是非常有用的,但我已經找到了另一種方式來做到這一點,我會體驗一下,並在稍後發佈! (但我保持你int touch!) – CollioTV 2014-10-03 08:26:47

    +0

    如果你想知道爲什麼我不接受你的答案是你做的方式,參數扣除將在編譯時完成,但我想要的是在運行時扣除! – CollioTV 2014-11-04 13:35:10