脚本库和函数模板
scripting library and function templating
上下文
我目前正在开发自己的库,用于在c++应用程序中加载自定义脚本。这里有一些示例代码来解释它的作用:
- 脚本部分:
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
}
问题
CCD_ 1对变量的访问和使用非常简单,但我的主要问题在其他地方:
- 在c++中,我如何保存和调用具有differents原型的方法/函数
- 编译器的一些技巧可以让它变得更容易吗?(比如知道参数的类型和数量?)
当前解决方案
让用户定义一个子函数,如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") {}
}
所以
有没有什么技巧或方法可以让我在库中更容易地使用函数/方法?(比如用编译器构建这些函数?(不要这么认为,但最好问一下)
编辑
有消息!我有自己的答案,我会把它贴出来(但有点长)(顺便说一句,英语不是我的母语,所以如果我犯了错误,我会编辑)
执行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);
另一种方法是提供一个arguments
变量,并让用户获得一个传递的参数,如arguments.get<T>(index)
上下文细节
为了获得更多的理解(如果想重用我的解决方案),我将详细介绍我正在做的事情的上下文:
- 有一个顶层(只能由
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;
};
和子函数(一个带有无效返回,另一个带有键入返回)
/*
* 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){}
};
现在是拆包工的工作
首先,我需要从std::vector
中打开我的arguments
/*
* 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());
}
};
到此为止
如果你想知道更多细节,请联系我!
相关文章:
- 当函数模板参数是具有默认参数的类模板时,函数模板参数的推导如何执行
- 将重载的成员函数传递给函数模板
- C++17中函数模板中的静态数组初始化(MSVC 2019)
- 为什么 gcc 和 clang 为函数模板的实例化生成不同的符号名称?
- 具有常量引用参数的函数模板专用化
- std::span<const T> 作为函数模板中的参数
- 如何编写一个完美的缩写函数模板?
- 仅在函数模板中为那些定义了函数的类型执行函数
- 如何在C++中伪造虚拟可变参数函数模板?
- 以下代码中的函数模板有什么问题?
- 在 C++20 中是否不再允许在 std 中对程序定义类型的函数模板进行专用化?
- 将显式实例化的函数模板与转换匹配
- 使用定义函数模板别名
- 函数模板返回类型
- C++有什么方法可以在既不调用函数模板也不提供其模板参数的情况下引用函数模板?
- C++ std::functional 中的可变参数函数模板
- 单行函数模板 c++ 的内联性保证
- C++函数模板需要 &for 数组参数
- 概念解析为使用 std::make_signed_t 时意外的函数模板
- 脚本库和函数模板