mpq_class
and Templated ReadingA generic piece of template code probably won’t know that mpq_class
requires a canonicalize
call if inputs read with operator>>
might be non-canonical. This can lead to incorrect results.
operator>>
behaves as it does for reasons of efficiency. A
canonicalize can be quite time consuming on large operands, and is best
avoided if it’s not necessary.
But this potential difficulty reduces the usefulness of mpq_class
.
Perhaps a mechanism to tell operator>>
what to do will be adopted in
the future, maybe a preprocessor define, a global flag, or an ios
flag
pressed into service. Or maybe, at the risk of inconsistency, the
mpq_class
operator>>
could canonicalize and leave mpq_t
operator>>
not doing so, for use on those occasions when that’s
acceptable. Send feedback or alternate ideas to gmp-bugs@gmplib.org.
Subclassing the GMP C++ classes works, but is not currently recommended.
Expressions involving subclasses resolve correctly (or seem to), but in normal C++ fashion the subclass doesn’t inherit constructors and assignments. There’s many of those in the GMP classes, and a good way to reestablish them in a subclass is not yet provided.
A subtle difficulty exists when using expressions together with
application-defined template functions. Consider the following, with T
intended to be some numeric type,
template <class T> T fun (const T &, const T &);
When used with, say, plain mpz_class
variables, it works fine: T
is resolved as mpz_class
.
mpz_class f(1), g(2); fun (f, g); // Good
But when one of the arguments is an expression, it doesn’t work.
mpz_class f(1), g(2), h(3); fun (f, g+h); // Bad
This is because g+h
ends up being a certain expression template type
internal to gmpxx.h
, which the C++ template resolution rules are unable
to automatically convert to mpz_class
. The workaround is simply to add
an explicit cast.
mpz_class f(1), g(2), h(3); fun (f, mpz_class(g+h)); // Good
Similarly, within fun
it may be necessary to cast an expression to type
T
when calling a templated fun2
.
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 provides several new ways in which types can be inferred: auto
,
decltype
, etc. While they can be very convenient, they don’t mix well
with expression templates. In this example, the addition is performed twice,
as if we had defined sum
as a macro.
mpz_class z = 33; auto sum = z + z; mpz_class prod = sum * sum;
This other example may crash, though some compilers might make it look like
it is working, because the expression z+z
goes out of scope before it
is evaluated.
mpz_class z = 33; auto sum = z + z + z; mpz_class prod = sum * 2;
It is thus strongly recommended to avoid auto
anywhere a GMP C++
expression may appear.