bool beats int

Well, I'm testing the operator + function for my biginteger class, and so I wrote myself a little function to add by integer and one to add by biginteger.

1
2
biginteger operator + ( intmax_t n ) const { ... }
biginteger operator + ( const biginteger& that ) const { ... }

Of course, my test case looks like this:

1
2
a = 9999;
b = a + 9;

But the compiler starts spewing errors because it can't figure out which operator to use. Next I add a whole bunch of overloads for int, unsigned, long, and unsigned long, short, etc, thinking that it needed an exact match.

Nope.

So I get rid of everything except operator + ( const biginteger& ) const, since the constructor takes all kinds of stuff (so that bigintegers can be automatically constructed from a variety of integers and strings).

Still doesn't work.

So after googling around a bit I try moving definitions outside the class, using non-reference arguments, etc. (I figured this was bunk, but it was worth trying.)

Eventually I just commented out all arithmetic operators. Surprisingly, it still compiled. This confused me. The sum of 9999 and 9 was... 10.

After looking around, I found and commented out operator bool () const.

Lo and behold, it suddenly began working!

???

Since when does that make sense?




Stupid C++.



On an unrelated note, or related, I'm not sure, here's some fun I found while googling:
http://www.steike.com/code/useless/evil-c/
I like the "goes toward" operator.
So, here's the question. Having figured the compiler out, there are a few ways to implement, say, addition by int.

1. I could keep the code very simple and just have it automatically convert all integer values to a biginteger in order to perform the arithmetic. (It is, though, very important to have a 'multiply by int' function -- but this could be made as a non-operator, protected member function.)

2. I could expose a single method to accept a signed integer value. This, of course, means that there are some integer literals that the user cannot use -- this might prove annoying. (I'm inclined to support every literal the user might supply -- the first option does this.)

3. Make the usual plethora of overloads (add by [unsigned] long|int in addition to the [u]intmax_t and biginteger_t<> types).

There may be other options I am unaware of... but currently I am trying to decide between 1 and 3. A temporary biginteger the size of a machine integer has so little cost it might not be worth option 3.

I have never written a professional-grade integer class before, so all this operator weirdness is a bit new to me. I want to be sure to be most usable (without hidden gotcha's).

Am I making the right choice (with option 1)?
I attempted a student project once that involved something like this. The design choices made me switch the project. Very humiliating confession, actually.

The answer depends on how do you expect the class to be used.
1) If the big integer is mainly used as temporary result from some operation to avoid overflow of the native types (and then the result is immediately rescaled like in fixed point arithmetic), or for long term accumulation of smaller quantities, then overloaded operators may be more interesting.
2) On the other hand, if the user performs big integer arithmetic all over the place, and keeps most quantities as big integers, then the infrequent penalty for the entry conversion and what have you is IMHO not a problem.

Templates may be used for the overloads. Templates are always pain, though.
Regards

EDIT: The arithmetic operators should preferably be defined as global friend functions instead of methods. When they are methods the first operand does not undergo implicit conversions.
Last edited on
The penalty for integer to biginteger conversion is so small as it is that I think I'll stick with option one.

Thank you! Your comments really did help. :-)
Topic archived. No new replies allowed.