我目前正在使用自己的库来加载c ++应用程序中的自定义脚本。 这里有一些示例代码,用于解释它正在做什么:
test.ctv
script
{
object player = access("player");
player.posX = 1 + 2;
access("map").load("map.txt");
}
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
的变量访问和使用非常简单,
但我的主要问题是在其他地方:
让用户定义像AccessibleLoad
:
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 :(得分:1)
做C ++ - &gt;你的脚本调用。顺便说一下,这是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);
除此之外,您可以做的最好的事情是提供arguments
变量并让用户获得传递的参数,如arguments.get<T>(index)
答案 1 :(得分: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;}
};
父函数类(用于存储它们):
class functionLoadable : public Loadable{
public:
virtual void call(parametersPack& pack) = 0;
};
和子功能(一个带有void返回,另一个带有typed-Return)
/*
* 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&lt;&gt;或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());
}
};
如果您想了解更多细节,请加油!