Removing Virtual Inheritance
I am working on an embedded project I am trying to remove a virtual number class that has + / - * implemented. removing this class saves a lot of code space so I have replaced + with the following function,
if (BASE(h)->type() == FLOAT && BASE(v)->type() == FLOAT)
{
res = FLOAT(h)->floatValue() + FLOAT(v)->floatValue();
}
else if (BASE(h)->type() == INTEGER && BASE(v)->type() == INTEGER)
{
res = INTEGER(h)->intValue() + INTEGER(v)->intValue();
}
else if (BASE(h)->type() == INTEGER && BASE(v)->type() == FLOAT)
{
res = INTEGER(h)->floatValue() + FLOAT(v)->floatValue();
}
else
{
res = FLOAT(h)->floatValue() + INTEGER(v)->floatValue();
}
Is there a less uglier way to 开发者_如何转开发achieve this? cause I have to use the same scheme for other ops and comparison?
#define GETFLOAT(arg) (BASE(arg)->type() == INTEGER ? INTEGER(arg)->floatValue() : FLOAT(arg)->floatValue())
switch(BASE(h)->type()) {
case INTEGER:
if (BASE(v)->type() == INTEGER) {
res = INTEGER(h)->intValue() + INTEGER(v)->intValue();
break;
}
case FLOAT:
res = GETFLOAT(h) + GETFLOAT(v);
}
This actually branches on the type of h
twice, but only in the case that (you say in a comment elsewhere) is expensive anyway, the floating-point op. You could avoid that with a goto
, but I'm not going to have that argument again. Something like:
switch(BASE(h)->type()) {
case INTEGER:
if (BASE(v)->type() == INTEGER) {
res = INTEGER(h)->intValue() + INTEGER(v)->intValue();
goto finished; // or better: return res;
}
hvalue = INTEGER(h)->floatValue()
break;
case FLOAT:
hvalue = FLOAT(h)->floatValue();
}
res = hvalue + GETFLOAT(v);
finished:
As with Howard's answer, if BASE()
or type()
is expensive then you could calculate the answer for each argument once, even though it's used twice.
What about doing it in two steps?
isInt1 = BASE(h)->type()==INTEGER;
isInt2 = BASE(v)->type()==INTEGER;
if (isInt1 && isInt2)
op1 = INTEGER(h)->intValue();
op2 = INTEGER(h)->intValue();
res = op1 + op2;
else {
op1 = isInt1 ? (FLOAT(h)->floatValue()) : (INTEGER(h)->floatValue());
op2 = isInt2 ? (FLOAT(v)->floatValue()) : (INTEGER(v)->floatValue());
res = op1 + op2;
}
I recommend reconsidering your architecture. How much have you saved with this approach, and how much has it cost in performance? Your new approach appears pushes everything to a float (you didn't show the declaration of res
, which I presume is float res;
.
Examine what this fix does to something like (a+b)*c
, where each of a, b, and c are (were) integers. With this fix at hand, you now have a float times an int, which is a lot more expensive computationally than an int times an int.
I suggest using templates and letting C++ type system handle as much of the conversion as possible. This lets you use disparate storage types that don't have to have common virtual base class.
You can also cut down on program size by implementing only one of int+float versus float+int (and similarly with int*float versus float*int). Temporarily implement both int+float and float+int, but intentionally make one raise a compile-time error. Flip the order of the operands where you get failures.
精彩评论