Objects and Lists
In order to help with managing Tcl lists, there is an object wrapper that allows to manipulate Tcl objects.The class
object
provides the following members:1. Constructors
object();
explicit object(bool b);
object(char const *buf, size_t size);
explicit object(double b);
explicit object(int i);
template <class InputIterator>
object(InputIterator first, InputIterator last);
explicit object(long i);
explicit object(char const *s);
explicit object(std::string const &s);
The above constructors allow to create a Tcl object from common C++ types.
The constructor accepting iterators is for the list creation. The provided iterator type should give either
object
or Tcl_Obj*
type when dereferenced.2. Copy constructors
explicit object(Tcl_Obj *o, bool shared = false);
object(object const &other, bool shared = false);
If the
shared
flag is set, the newly created object
wrapper will not duplicate the underlying Tcl object.3. Assignment-related members
object & assign(bool b);
object & resize(size_t size); // byte array resize
object & assign(char const *buf, size_t size); // byte array assignment
object & assign(double d);
object & assign(int i);
template <class InputIterator>
object & assign(InputIterator first, InputIterator last);
object & assign(long l);
object & assign(char const *s);
object & assign(std::string const &s);
object & assign(object const &o);
object & assign(Tcl_Obj *o);
object & operator=(bool b);
object & operator=(double d);
object & operator=(int i);
object & operator=(long l);
object & operator=(char const *s);
object & operator=(std::string const &s);
object & operator=(object const &o);
object & swap(object &other);
The
assign
member function accepting iterators is for the
list assignment. The provided iterator type should give either object
or Tcl_Obj*
type when dereferenced.4. Non-modifying accessors
template <typename T>
T get(interpreter &i) const;
char const * get() const; // string get
char const * get(size_t &size) const; // byte array get
size_t length(interpreter &i) const; // returns list length
object at(interpreter &i, size_t index) const;
Tcl_Obj * get_object() const { return obj_; }
The
get<T>
template is specialized for the
following types:bool
vector<char>
(for byte array queries)double
int
long
char const *
std::string
object & append(interpreter &i, object const &o);
object & append_list(interpreter &i, object const &o);
template <class InputIterator>
object & replace(Interpreter &i, size_t index, size_t count,
InputIterator first, InputIterator last);
object & replace(interpreter &i, size_t index, size_t count, object const &o);
object & replace_list(interpreter &i, size_t index, size_t count, object const &o);
6. Additional helpers
void set_interp(Tcl_Interp *interp);
Tcl_Interp * get_interp() const;
These functions may help to transmit the information about the "current" interpreter when the C++ function accepting
object
parameter is called from Tcl.The
set_interp
function is automatically called by the
underlying
conversion logic, so that the C++ code can use the other function for
accessing the interpreter.This may be useful when the C++ code needs to invoke other functions that may change the interpreter state.
Note: If there is any need to extract the interpreter from the existing object, it may be helpful to wrap the resulting raw pointer into the
interpreter
object, which will not disrupt its normal lifetime:interpreter i(o.get_interp(), false);
The second parameter given to the
interpreter
constructor
means that the newly created i
object will not claim
ownership to the pointer received from get_interp()
.In other words, the destructor of the object
i
will not
free the actual interpreter.Example:
The following complete program creates the list of numbers, sorts it using the Tcl interpreter and prints the results on the console (note: this is not the most efficient way to sort numbers in C++!):
// example6.cc
#include "../cpptcl.h"
#include <iostream>
using namespace std;
using namespace Tcl;
int main() {
interpreter i;
int numbers[] = {5, 7, 1, 6, 3, 9, 7};
size_t elems = sizeof(numbers) / sizeof(int);
object tab;
for (size_t indx = 0; indx != elems; ++indx) {
tab.append(i, object(numbers[indx]));
}
object cmd("lsort -integer");
cmd.append(i, tab);
// here, cmd contains the following:
// lsort -integer {5 7 1 6 3 9 7}
object result = i.eval(cmd);
cout << "unsorted: ";
for (size_t indx = 0; indx != elems; ++indx) {
cout << numbers[indx] << ' ';
}
cout << "\n sorted: ";
elems = result.length(i);
for (size_t indx = 0; indx != elems; ++indx) {
object obj(result.at(i, indx));
int val = obj.get<int>(i);
cout << val << ' ';
}
cout << '\n';
}
When this program is run, it gives the following output:
$ ./example6
unsorted: 5 7 1 6 3 9 7
sorted: 1 3 5 6 7 7 9
$
In this example, an empty
tab
object is created and all
numbers are appended to it to form a Tcl list of numbers.After that, the sorting command is composed and executed (as you see, the
object
can be passed for evaluation).The result of the command is retrieved also in the form of object wrapper, which is used to decompose the resulting list into its elements.