Previous: , Up: C++ Class Interface   [Index]


12.6 C++インターフェースの制限

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+hgmpxx.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

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の使用は避けて下さい。