Project Idea: Sudoku Solver

Pages: 12
@Duoas : For your if (X < Y < Z) replacement you could use what I do.

1
2
3
4
#define ZERO 1e-10
#define isBetween(A, B, C) ( ((A-B) > -ZERO) && ((A-C) < ZERO) )

if (isBetween(Y, X, Z)) { }


We use it for double comparisons etc
I've done that. The problem is that it isn't visually explicit. Personally I would want to know that X is between Y and Z. But back when I was doing assembly I would have thought Y is between X and Z. Of course, being able to look at the code or specifications gives the answer, but given all the things there are to remember... I would have to look it up every time I saw it --which gets old fast.

It is also a #define, which I've learned can bite you in dangerous ways. For example, what if I say:
1
2
3
4
int n = 19;
// Is the lower byte of n between 50 and 200?
if (isBetween( n & 0xFF, 50, 200 ))
  apparently();

It fails because operator precedence boogered the equation. Of course this example makes it obvious, but how often are the quantities so neatly given or known beforehand?


So we try to fix it with:

#define isBetween(A, B, C) ( (((A)-(B)) > -ZERO) && (((A)-(C)) < ZERO) )

That'll solve the operator precedence problem, but it leaves you wide open for this:
1
2
3
int n = 100;
while (isBetween( n = recalc( n ), 50, 90 ))
  cout << n << endl;

Once again, the programmer has to know exactly how the macro is defined to avoid it, and he has to write something more obtuse like
1
2
while (n = recalc( n ), isBetween( n, 50, 90 ))
  cout << n << endl;

which makes no sense to anyone but those who remember that isBetween is a macro trap. Someone, months or years from now, will say, "what?" and 'fix' it as they go about their duties. Then spend months of maintenance time trying to figure out where the error is.


The following site is the first one that popped up for me in Google, but it is part of the standard CPP documentation which lists all these problems with macros and more:
http://developer.apple.com/documentation/DeveloperTools/gcc-4.0.1/cpp/Macro-Pitfalls.html#Macro-Pitfalls


Another problem I have with it is that it doesn't template on anything but numeric types that can promote to floating point --essentially throwing away all the power you get from operator overloading. I can't, for example, say:
1
2
string names[] = { "derrik", "alexis", "hannah" };
if (isBetween( names[0], names[1], names[2] )) ...

I would have to go the long way around and do the macro's magic myself.

if ((names[1] < names[0]) && (names[0] < names[2])) ...

Using code templates enable you to have: type checking, namespace management, non-numeric ordered types, and more succinct code.


I have settled with defining two ranger constructors: ranger() and R(), and letting the user import the one he wants. So I can say:
1
2
if (R( 0 ) <= index < length_of_x)
  foo = x[ index ];

and
1
2
string name = "derrik";
if (R( "alexis" ) < name < "hannah") ...


Sure, it still has that funny-looking 'R' or 'ranger' in there, but the code is instantly readable and the purpose and use of R can be surmised without having to refer to its documentation.

Hence the time I spent developing it.

Whew. Hope I answered your question...
Indeed I agree with this, but for a specific application with a known purpose, known limits and constraints on the data then that macro will do.

If you are building an enterprise scale application that has to manage multiple data types then you should be using correctly implemented overloads.

If your application has a specific functionality, with known data types then using a macro is fine. It's more a solution to fit the problem, than a 1 solution for all problems situation.

I find it odd that you are able to do if (X < Y < Z) by using your construct. How does your construct change the rules of the If Conditional?
Last edited on
Magic.

:-)




Actually, it doesn't. R() returns a templated object that overloads the bool() and void*() operators, and then I overload all three combinations for each of the six comparison operators. (I do it by using a local macro. :-> ). If you want I'll post the code.

It does have an obnoxious side-effect though: it produces the "comparisons like X<=Y<=Z do not have their mathematical meaning" warning message when compiling with strict warnings on. The GCC people don't believe you should be able to #pragmatize away specific warnings -- they want it on or off for an entire module. I can do it with VC++, and I'm pretty sure C++Builder can do it too, but I haven't bothered to look that far because it isn't worth the effort to add-in a ton of compiler-specific stuff that may or may not even work...

With GCC at least I can get rid of the warning just by using extra parentheses... which in this case looks really lame.
I do find it interesting how cout << x << y << z; doesn't produce those messages, even though it makes far less sense than multiple comparisons, no?

:-P
Topic archived. No new replies allowed.
Pages: 12