views:

149

answers:

6

One can do this:

case WM_COMMAND:
if (WORD wNotifyCode = HIWORD(wparam))
{
  ...
}

And one can do this:

case WM_COMMAND:
{
  WORD wNotifyCode = HIWORD(wparam);
  if (wNotifyCode > 1) {
    ...
  }
}

But one cannot do:

case WM_COMMAND:
if ((WORD wNotifyCode = HIWORD(wparam)) > 1)
{
  ...
}

Using a for statement here I think is misleading:

case WM_COMMAND:
for (WORD wNotifyCode = HIWORD(wparam); wNotifyCode > 1; wNotifyCode = 0)
{
  ...
}

Because it looks a lot like a loop is happening - and the poor schmuck who comes after me has to decipher this garbage.

But is there no syntactic construct which combines the elegance of an if-statement that includes a local variable declaration with the ability to test its value for something other than zero?

A: 

You could modify your test a bit:

if (WORD wNotifyCode = HIWORD(wparam) - 1)

if you want to check if wNotifyCode > 1.

dirkgently
Well, `!= 1` really, but I guess we're assuming that `WORD` is something like a `uint16_t`? Anyhow, I like this bit of cleverness, although the code in the following block has to be careful that `wNotifyCode` is one off from what it would have been.
ephemient
!= 1? The OP sample was `> 1` which this achieves. And yes, of course, you will need to have that off by one in your mind.
dirkgently
Indeed - this leaves wNotifyCode = one less than it should be, which is not quite what I was hoping for.
Mordachai
sorry but -1 for magical and unreadable code :/ (more comments needed then just doing the variable outside of the condition and introducing a separate scope)
RnR
@RnR: Did you even read the OP's question? This is taken almost verbatim from one of his examples.
dirkgently
And? Does it mean it's correct or a good coding practice? ;)
RnR
How does this check `> 1`? If `WORD` is signed, and you get a `-4` back, then `-4-1 == -5` still passes the `if`.
ephemient
@RnR: There's something called context. In _this_ context, style and good coding practice wasn't involved. As for correct, I'd stand by my answer because that is possibly the closest to what the OP wants w/ the syntax the language offers.
dirkgently
@ephemient: The post had enough hints that the OP is talking about MSVC. See: http://msdn.microsoft.com/en-us/library/cc230402%28PROT.10%29.aspx. We can argue further, but I think this is going no where.
dirkgently
@dirkgently - I bet you'd never suggest this solution in *any* context if you'd need to debug through this even once while looking for a problem ;)
RnR
@RnR: You are shifting from your initial argument. The code above is not magical nor unreadable. Dig into some image processing libraries -- there you see magical stuff. IMO, the OP asked for something within the syntactic framework and not a subjective opinion on style.
dirkgently
That's why I mentioned `uint16_t`: if `WORD` is unsigned, then fine.
ephemient
My initial argument was that this is "magical and unreadable" - how am I shifting from it by saying "you'd never suggest this solution in any context if you'd need to debug through this even once while looking for a problem"? As you see by other comments here you have to be: sure what the return type of HIWORD is and come up with how the overflow will result the implicit ==0 check, but most of all your code works ONLY for checking if it's != 1 and does not give the "ability to test its value for *something other than zero*" (the condition is true for wparam ==0 - vs2008 )
RnR
A: 

The following works for me

if (WORD nNotifyCode = HIWORD(test) > 1)
{
}

I'd hazard a guess, but don't know for sure, that the = operator has precedence over the > operator, and i know the outcome an assignment operation is the value of the assignment, the test works.

EDIT: [Putting Dunce Cap on, going to Corner]

Ruddy
Your guess is wrong. What you wrote is interpreted as `if (WORD nNotifyCode = (HIWORD(test) > 1))`, which is not what is intended. The assignment operator (and related operators like +=) have some of the lowest precedence of all operators. They're only higher than throw and , (comma).
Tyler McHenry
Doh - tested that way too fast. Yet another lesson for the day.
Ruddy
That is just wrong. This will apply the boolean expression `HIWORD(test) > 1` to `wNotifyCode`, resulting in 0 or 1. Not what he expects.
AndiDog
The assignment operators have lower precedence than almost anything, this will assign a bool converted to word to nNotifyCode.
meagar
Ruddy - its worth leaving wrong answers up to help others. I know I thought of your solution as well, and it happened to hit me that this would simply assign the wrong thing. But having others see that and save themselves the "would this work..." is valuable. We've all had d'oh! moments!!! ;)
Mordachai
@mordachai - its back for posterity.
Ruddy
Also, if you did want to delete the answer, there should be a "delete" option between "edit" and "flag"...
ephemient
@ephemient, yes it was there is, i clicked it - but it asked me if wanted to "vote" to delete the comment... at that point i wasn't sure how many votes were needed (perhaps only mine?) - in any case - i put it back and i'll take my, well deserved, lumps.
Ruddy
+1  A: 

Preprocessor tricks:

#define IF_2(init, test) \
    for (bool first_ = true; first_;) for (init; first_ && (test); first_ = false)

IF_2(WORD wNotifyCode = HIWORD(wparam), wNotifyCode > 1)
{
  ...
}

It's ugly and certainly no better than the options you already have.

ephemient
I'd much prefer macros in all uppercase; readability, less chance of making a typo.
dirkgently
sorry but -1 for magical and unreadable code :/ - it seems this cannot be done nicely so maybe it's better to not do it at all? ;)
RnR
Upvote because the author both answers how to do it, and says they don't recommend doing it that way. Remember folks: C++/C macros are evil! Strongly consider your cost/benefit, and wash your hands twice :)
Merlyn Morgan-Graham
+3  A: 

Sometimes readability and maintainability is more important then a line of code saved.

IF you need the local variable at all then by all means introduce it explicitly in this case and maybe introduce an additional scope if you want it limited - but you should also consider if maybe you can just live with using the HIWORD macro in a couple places - this way you don't need any tricks at all.

RnR
Again - C++ allows me to declare the variable in the scope implicitly defined by the if itself... so if I could just set the test conditions rather than being forced to use decay to scalar nonzero, I'd get the best of all possible worlds. I'll live with the extra scope for now. ;)
Mordachai
+1  A: 

Try introducing a helper function like this:

template <typename T>
T zeroIfLess(T val, T base)
{
  return val < base ? T(0) : val;
}

Then, write your condition as:

if (WORD wNotifyCode = zeroIfLess(HIWORD(wparam), 2))

That will return zero -- or, if you prefer, false -- if the first supplied value is less than the second; otherwise it returns the value. Given that it's hard to settle on the function's name, and whether it should take an inclusive or exclusive minimum, that it works here doesn't diminish it being a weird hack.

Like others have recommended, I too favor your first proposal after "And one can do this" -- the separate declaration and initialization statement followed by the conditional statement. I think that's just the natural way to do it in C++.

seh
+1  A: 

Tip: you could use the message cracker macros; in this way, you'd get a much shorter wndproc (without all those nested switches), your message handling code would be tidily split in separate functions (one for each message), and you almost wouldn't need all the HIWORD-LOWORD stuff, because the message-cracker macros do that for you and pass the information retrieved by lParam and wParam to you function already split in parameters.

Matteo Italia
Hadn't heard of the "message cracker macros". Are these what you are talking about?http://support.microsoft.com/kb/83456
Merlyn Morgan-Graham
Yes, they are; here (http://www.codeproject.com/KB/winsdk/msgcrackwizard.aspx) you can find a little introduction about them and a tool to help you with them (about which I know nothing).
Matteo Italia
Message crackers can be incredibly useful. In my particular case, I am already using MFC to break out the message handlers already - but wanted to insert a "pump blocker" for notification class messages during a given context. So I flag the context, and then don't propagate old WM_COMMAND *notifications* and new WM_NOTIFY notifications, but allow all other messages through to the normal message-map distribution handler. So breaking the messages out again, at this level, would be confusing to the actual purpose / architecture here. Still a good idea to use them in general! :)
Mordachai
Ok, I posted this just because many people that are in the situation of your original post don't know about them, and the message crackers solve these problems in normal wndprocs. :)
Matteo Italia