Previous: C++ Interface Random Numbers, Up: C++ Class Interface [Index]
mpq_class
とテンプレートの読み取り一般的なテンプレートでは,mpq_class
が,operator>>
を用いた読み取りの際に標準形でない有理数であればcanonicalize
関数の呼び出しを必要とする,ということを想定していません。このため,不正確な結果になることがあります。
operator>>
はなるべく高速になるように動作します。長いオペランドの場合は,標準形に直す操作に時間がかかるので,必要がない時にはなるべく避けるようにしましょう。
この潜在的な遅延はmpq_class
の使い勝手を悪くします。おそらくこのoperator>>
に関する仕様は,プリプロセッサの定義やグローバルフラグ,ios
フラグの利用で将来改善されるでしょう。あるいはmpq_class
operator>>
で標準形に直し,mpq_t
operator>>
ではそれをしない,という解決策を取るかもしれません。何か良い案があったらgmp-bugs@gmplib.orgにお寄せ下さい。
現在動いているGMP C++クラスをサブクラス化することは現段階では推奨しません。
サブクラス化された式表現は現在では(多分)正常に使えるでしょうが,標準的なC++のやり方ではサブクラスはコンストラクタや割り当てを継承しません。GMPのC++クラスにはこれが大量に入っているので,今のところこれらを全部含むサブクラス化の良い方法は提供されていません。
アプリケーションで定義したテンプレート関数を使った式表現を使うと,微妙におかしなことが起こり得ます。詳細については下記の,T
を使った数値データ型の事例を読んで考えて下さい。
template <class T> T fun (const T &, const T &);
生のmpz_class
変数を使えば,T
はそのままmpz_class
として解釈され,上記のコードは正しく動作します。
mpz_class f(1), g(2); fun (f, g); // Good
しかし,下記のように式表現を引数として与えてしまうと動作しません。
mpz_class f(1), g(2), h(3); fun (f, g+h); // Bad
これはg+h
がgmpxx.h
の内部的な式テンプレート表現型となってしまうことで,C++テンプレートの解釈ルールでは自動的にmpz_class
に変換できないという事由によるものです。解決策としては,強制的に型キャストしてしまうというものがあります。
mpz_class f(1), g(2), h(3); fun (f, mpz_class(g+h)); // Good
同様に, fun
の内部では,テンプレート宣言されたfunc2
の中で呼び出される時には,T
は式ではなくデータ型としてキャストされている必要があります。
template <class T> void fun (T f, T g) { fun2 (f, f+g); // Bad } template <class T> void fun (T f, T g) { fun2 (f, T(f+g)); // Good }
C++11ではデータ型を推測する機能としてauto
, decltype
等が追加されています。大変便利なものですが,式テンプレートに混ぜ込んで使わないようにして下さい。下記の例ではsum
がマクロのように定義され,加算が2回実行されてしまいます。
mpz_class z = 33; auto sum = z + z; mpz_class prod = sum * sum;
クラッシュしてしまう実例もお見せします。いくつかのコンパイラでは一見うまくいっているように見えますが,その実,z+z
が評価される前にスコープ外に放り出されてしまいます。
mpz_class z = 33; auto sum = z + z + z; mpz_class prod = sum * 2;
こういう事情があるので,GMP C++式表現に対してはゆめゆめauto
の使用は避けて下さい。