こんにちは、高木です。
今回もTcl_Obj型について見ていきます。前回はTcl_Obj型のオブジェクトに文字列を格納する話題でしたが、今回は数値を格納していきます。
Tclが扱える数値には次のものがあります。
- int型
- long型
- WideInt型
- Boolean型
- Bignum型
- double型
それぞれの型についてTcl_Obj型のオブジェクトを生成や値を取得するAPIが用意されています。詳しくは公式ドキュメントを参照してください。
ただ、先ほど挙げたすべての型に対応する必要はないと考えています。たとえば、long型は環境によって32ビットの場合と64ビットの場合があり、int型かWideint型のどちらかと同じサイズになります。よって、32ビット整数であるint型と64ビット整数であるWideInt型に対応すれば十分でしょう。
Bignum型というのは、LibTomMathという多倍長整数ライブラリーを使用しているのですが、外部ライブラリーのLibTomMathを要求するのではなく、Tclの中にLibTomMathを取り込んでしまっています。結果として、本来のLibTomMathを使いたい場合にいろいろ面倒が起きますので、文字列として扱うようにした方がよさそうです。
今回は、検討の結果残ったint型、WideInt型、Boolean型、double型についてのみ対応することにします。では、その部分のコードを抜粋してみましょう。
| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |     obj(std::int_least32_t value) : obj_(Tcl_NewIntObj(static_cast<int>(value)))     {       Tcl_IncrRefCount(this->obj_);     }     obj(std::int_least64_t value) : obj_(Tcl_NewWideIntObj(static_cast<Tcl_WideInt>(value)))     {       Tcl_IncrRefCount(this->obj_);     }     obj(bool value) : obj_(Tcl_NewBooleanObj(value))     {       Tcl_IncrRefCount(this->obj_);     }     obj(double value) : obj_(Tcl_NewDoubleObj(value))     {       Tcl_IncrRefCount(this->obj_);     }     std::optional<std::int_least32_t> get_int() const     {       extern Tcl_Interp* root_interp;       int value;       if (Tcl_GetIntFromObj(root_interp, this->obj_, &value) == TCL_OK)         return static_cast<std::int_least32_t>(value);       return {};     }     std::optional<std::int_least64_t> get_wide_int() const     {       extern Tcl_Interp* root_interp;       Tcl_WideInt value;       if (Tcl_GetWideIntFromObj(root_interp, this->obj_, &value) == TCL_OK)         return static_cast<std::int_least64_t>(value);       return {};     }     std::optional<bool> get_boolean() const     {       extern Tcl_Interp* root_interp;       int value;       if (Tcl_GetBooleanFromObj(root_interp, this->obj_, &value) == TCL_OK)         return static_cast<bool>(value);       return {};     }     std::optional<double> get_double() const     {       extern Tcl_Interp* root_interp;       double value;       if (Tcl_GetDoubleFromObj(root_interp, this->obj_, &value) == TCL_OK)         return static_cast<double>(value);       return {};     } | 
ほとんど同じことの繰り返しになっています。こういうコードは、本来であればPHPで前処理して自動生成したいところですね。
int型とWideInt型には、C++のコードではstd::int_least32_t型とstd::int_least64_t型を使うようにしました。その方が意図が明確になりますので。また、get_*メンバー関数内ではroot_interpというTcl_Interp*型のグローバル変数を参照しています。Tcl_Obj型から数値を取り出すためにはどうしても必要になるからです。いまいちなのですが、インタープリターについてはまだラッパークラスを用意していませんので、今のところはとりあえずこれで進めます。
これで一通りTcl_Obj型と数値の相互変換ができるようになりました。まだ少しだけTcl_Obj型のラッパークラスであるobjクラスについては触れておかないといけないことがありますので、次回はその話題を取り上げることにします。


![[迷信] コンストラクタから例外を送出してはならない](https://www.kijineko.co.jp/wp-content/uploads/2021/06/2219843_s.jpg)



![[C11] 第8回 構造体と共用体と列挙体](https://www.kijineko.co.jp/wp-content/uploads/2021/10/22653998_s.jpg)