扩展自由函数
上页的例子已经简单显示了如何在Tcl解释器中添加一个由C++函数实现的新命令。无论以什么方式使用Tcl解释器(模块或嵌入式),为Tcl扩展命令的方法都是一样的:
i.def("tcl_function_name", cpp_function_name);
其中
i
是Tcl解释器对象,
字符串"tcl_function_name"
定义了新命令在Tcl解释其中的命令名,函数名
cpp_function_name()
则告诉了Tcl解释器新命令在C++程序中的对应执行函数。Tcl命令名和其对应的C++函数名不需要一样,C++/Tcl解释器对象会自动记录它们的对应关系。不过大多数时候取相同的名字有助于程序的可读性,正如上页中的例子:
i.def("hello", hello);
事实上,任何符合Tcl命令名规定的名字都可作为
def()
函数的第一个参数。比如说,我们需要将下面的C++函数扩展成Tcl命令。
int sum(int a, int b) {
return a + b;
}
我们可以这样定义新Tcl命令:
i.def("sum", sum);
i.def("+", sum);
定义完成后,我们就可以在Tcl解释器中用如下的方式调用C++程序中的
sum()
函数:add 3 4
或者(后序表达式):
+ 3 4
正如你看到的,你可以用同一个C++函数定义多个不同的Tcl命令。
如果同一个Tcl命令被定义多次,最后一次定义的C++函数将覆盖前面的定义。你可以使用该方式覆盖Tcl原有命令的默认定义。
当然,被扩展的命令可以有输入参数和返回值。
当函数的输入参数数量小于等于9个,并且所有的参数类型(包括返回值类型)为如下类型时,C++/Tcl将自动处理函数的参数与返回值定义。
当前C++/Tcl库可以自动处理的参数或返回值类型包括以下几种:
- std::string, char const *
- int,
- long,
- bool,
- double,
- pointer to arbitrary type
- object
object
为Tcl数据对象,可作为万能类型使用(用以支持非以上类型的复杂类型)。此外,参数的类型定义可为拷贝类型(类型本身)或者常数引用类型(
T
const &
,其中T
为类型),C++/Tcl库可以自动处理。也就是说,被扩展的命令只有输入型参数(函数不能直接改变外部数据)。
Starting from version 1.1.4, the last argument of the C++ function can be used to pass an environment data (currently it must be a pointer) to the function, which is realized by using the ClientData field of the Tcl APIs. The following example shows the usage of this extra argument:
// example test7.cc
#include "cpptcl.h"
static int gdata = 2; // a global data
void fun(int d, int * gd) { // gd comes from environment
*gd += d;
}
int main() {
interpreter i;
i.def("fun", fun, &gdata); // send gdata to the Tcl fun
i.eval("fun 10"); // only one argument is passed by Tcl command
assert(gdata == 12); // check the global data is changed
return 1;
}
For variadic functions, the generic
object
type should be the
second last argument if the last one is used for environment data. Such as:// a function with 3 typed arguments, one variadic object and one environment data
double fun(int d1, long d2, std::string d3, const object& var_arg, void * any_pointer);