| 1 | /*
|
|---|
| 2 | Ulrich Mutze 2016-06-23
|
|---|
| 3 |
|
|---|
| 4 | Title:
|
|---|
| 5 | ------
|
|---|
| 6 | User-defined conversion operator from a wrapper class to a
|
|---|
| 7 | boost/multiprecision floating-point type does not compile.
|
|---|
| 8 |
|
|---|
| 9 | The observation:
|
|---|
| 10 | ---------------
|
|---|
| 11 | With the first of the two typedefs in action the file does not compile.
|
|---|
| 12 | Commentarizing the first typedef and activating the second lets
|
|---|
| 13 | everything work fine.
|
|---|
| 14 | According to the rules of C++ it should work in both cases.
|
|---|
| 15 | That it does not has probably to be considered a bug in the
|
|---|
| 16 | boost/multiprecision class system. It conflicts with the statement
|
|---|
| 17 | "It acts as an entirely C++ (header only and dependency free) floating-point number type that is a drop-in replacement for the native C++ floating-point types, but with much greater precision."
|
|---|
| 18 | of the documentation to cpp_bin_float.
|
|---|
| 19 |
|
|---|
| 20 | The context:
|
|---|
| 21 | -----------
|
|---|
| 22 | In my large C++ class system ( referred to as C+- in uuu.ulrichmutze.de) which originally did not enable multiprecision, I typedefed the floating-point type to be used througout the entire code base as
|
|---|
| 23 | typedef double (or float or long double) R;
|
|---|
| 24 | Here R stands for the set of real numbers as used in mathematics and not
|
|---|
| 25 | for the statistics-oriented software system R.
|
|---|
| 26 | In developing classes to be used in physics simulations it turned out
|
|---|
| 27 | often to be necessary to give a class an additional R-typed member.
|
|---|
| 28 | Since the built-in types get not automatically initialized, in such a case
|
|---|
| 29 | I had to extend the constructor initializer list in all the many constructors of my class by hand which was tedious and error-prone.
|
|---|
| 30 | So I decided to have floating-point data members in the form
|
|---|
| 31 | R1 x_;
|
|---|
| 32 | with a wrapper class R1 as defined in the following code. Using x_
|
|---|
| 33 | somewhere in an arithmetic expression would automatically convert it to R
|
|---|
| 34 | just as I had introduced it as
|
|---|
| 35 | R x_;
|
|---|
| 36 | When I enabled multiprecision my first option was
|
|---|
| 37 | typedef mpfr::mpreal R;
|
|---|
| 38 | and everything worked well with this "drop-in replacement".
|
|---|
| 39 | See my work:
|
|---|
| 40 | Precision-dependent symmetry breaking in simulated motion of
|
|---|
| 41 | polyspherical grains (2009)
|
|---|
| 42 | http://uuu.ma.utexas.edu/mp_arc/c/09/09-113.pdf
|
|---|
| 43 | Ironically the wrapper R1 was no longer necessary in principle since now
|
|---|
| 44 | R-typed data members would have been initialized as R(0) automaticaly.
|
|---|
| 45 | However, the bit of extra complexity did no harm and was still necessary
|
|---|
| 46 | for the normal mode of my programs in which R was an alias for double.
|
|---|
| 47 | Of course, my expectation was that replacing mpreal by any of the
|
|---|
| 48 | boost multiprecision floating point types would work the same way. Unfortunately this turned out to be a pre-mature expectation. My hope is
|
|---|
| 49 | that digging out the reason for this strange behavior will give hints
|
|---|
| 50 | how the boost multiprecision floating-point types can be promoted to
|
|---|
| 51 | real "drop-in replacements" of type double.
|
|---|
| 52 |
|
|---|
| 53 | The code:
|
|---|
| 54 | ---------
|
|---|
| 55 | */
|
|---|
| 56 | #include <iostream>
|
|---|
| 57 | #include <boost/multiprecision/cpp_bin_float.hpp>
|
|---|
| 58 |
|
|---|
| 59 | using namespace std;
|
|---|
| 60 | using namespace boost::multiprecision;
|
|---|
| 61 |
|
|---|
| 62 | typedef number<cpp_bin_float<50>, et_off > R;
|
|---|
| 63 | //typedef double R;
|
|---|
| 64 |
|
|---|
| 65 | //------------------------ class R1 ---------------------------------------
|
|---|
| 66 | class R1{ // wrapper class for R
|
|---|
| 67 | R x_;
|
|---|
| 68 | public:
|
|---|
| 69 | R1(void):x_(0.){}
|
|---|
| 70 | // explicit conversion R --> R1
|
|---|
| 71 | explicit R1(R const& a):x_(a){}
|
|---|
| 72 | // automatic conversion operator R1 --> R
|
|---|
| 73 | operator R()const{ return x_;}
|
|---|
| 74 | };
|
|---|
| 75 |
|
|---|
| 76 | int main()
|
|---|
| 77 | {
|
|---|
| 78 | cout.precision(50);
|
|---|
| 79 | R x=9.123456789123456789123456789;
|
|---|
| 80 | R y=5.678912345678901234567890123;
|
|---|
| 81 | R1 x1(x);
|
|---|
| 82 | R1 y1(y);
|
|---|
| 83 | R sum=x1+y1;
|
|---|
| 84 | // This has to work since x1 and x2 can be converted to
|
|---|
| 85 | // instances of R. It actually works for typedef double R;.
|
|---|
| 86 | // My German-speaking system says for
|
|---|
| 87 | // typedef number<cpp_bin_float<50>, et_off > R;
|
|---|
| 88 | // 'Keine Übereinstimmung für >>operator+<< in >>x1+y1<<'
|
|---|
| 89 | // my translation:
|
|---|
| 90 | // 'no match for >>operator+<< in >>x1+y1<<'.
|
|---|
| 91 | cout << " x = "<<x<<endl;
|
|---|
| 92 | cout << " y = "<<y<<endl;
|
|---|
| 93 | cout << " sum = "<<sum<<endl;
|
|---|
| 94 | return 0;
|
|---|
| 95 | }
|
|---|