The following code works fine (compiles, assert statement gives true) under Linux/Debian (g++ 10.2), but refuses to work under Windows (mingw64 g++ 12.2.0). It’s basically just supposed to assign UINT64_MAX
to a mpf_class
from the gmp library, but it seems gmp’s mpf_class
defines no constructor and no operators for uint64_t
, which is unsigned long long int in the windows environment I’m trying to work with here. I bet there is a simple workaround I’m not seeing right now, because it’s friday and late, correct?
#include <gmpxx.h> // link with gmp + gmpxx
#include <string>
/// Helper to convert mpf_class to std::string
[[nodiscard]] inline std::string mpf_class_to_str(const mpf_class& num) {
mp_exp_t exponent(1);
return num.get_str(exponent, 10);
}
int main() {
mpf_class y = UINT64_MAX; // defined in my mingw64 as 0xffffffffffffffffULL
// ^
// | adding no cast -> compile error
// adding (unsigned int) cast -> compiles, but assertion below false
// adding (uint64_t) cast -> compile error
y *= UINT64_MAX; // UINT64_MAX²
assert(mpf_class_to_str(y) == "340282366920938463426481119284349108225");
}
The compile error g++ gives me is:
error: conversion from 'long long unsigned int' to 'mpf_class' is ambiguous
31 | mpf_class y = UINT64_MAX;
| ^~~~~~~~~~
and then it lists all candidates, which basically are (taken from gmpxx.h
instead of the error log):
#define __GMPXX_DEFINE_ARITHMETIC_CONSTRUCTORS
__gmp_expr(signed char c) { init_si(c); }
__gmp_expr(unsigned char c) { init_ui(c); }
__gmp_expr(signed int i) { init_si(i); }
__gmp_expr(unsigned int i) { init_ui(i); }
__gmp_expr(signed short int s) { init_si(s); }
__gmp_expr(unsigned short int s) { init_ui(s); }
__gmp_expr(signed long int l) { init_si(l); }
__gmp_expr(unsigned long int l) { init_ui(l); }
__gmp_expr(float f) { init_d(f); }
__gmp_expr(double d) { init_d(d); }
If I manipulate that header adding the line __gmp_expr(unsigned long long int l) { init_ui(l); }
all is well except this is too dirty of a fix even for me.
2
Answers
Besides patching the gmp library as suggested in user17732522's answer it's also possible to get my example to work by using a conversion helper function. Something like this:
And changing the usage accordingly:
Now it compiles and the assertion gives true in both - my Linux and Windows environment.
mpz_class
cannot be constructed from a(unsigned) long long
. That is also stated in the documentation.The library does not support
(unsigned) long long
. See the mailing list thread here (and several older ones). In the answer Marc Glisse also points out that this is mainly an issue on Windows.He also suggested a patch for support of the C++ initialization/conversion part of the problem here, but I couldn’t find it on gmp’s public development repository yet. As he points out in the message, this would not cover arithmetic operations and such though.