View on GitHub

Cpptcl

C++/Tcl——辅助实现嵌入式Tcl解释器的C++接口库

English 中文

Download this project as a .zip file Download this project as a tar.gz file
[上一页] [顶层] [下一页]

扩展自由函数

上页的例子已经简单显示了如何在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库可以自动处理的参数或返回值类型包括以下几种: 其中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);