Reputation: 11317
void main()
{
int xyz = 123; // original value
{ // code block starts
xyz++;
if(xyz < 1000)
xyz = 1;
} // code block ends
int original_value = xyz; // should be 123
}
void main()
{
int xyz = 123; // original value
MACRO_NAME(xyz = 123) // the macro takes the code code that should be executed at the end of the block.
{ // code block starts
xyz++;
if(xyz < 1000)
xyz = 1;
} // code block ends << how to make the macro execute the "xyz = 123" statement?
int original_value = xyz; // should be 123
}
Only the first main()
works.
I think the comments explain the issue.
It doesn't need to be a macro but to me it just sounds like a classical "macro-needed" case.
By the way, there's the BOOST_FOREACH
macro/library and I think it does the exact same thing I'm trying to achieve but it's too complex for me to find the essence of what I need.
From its introductory manual page, an example:
#include <string>
#include <iostream>
#include <boost/foreach.hpp>
int main()
{
std::string hello( "Hello, world!" );
BOOST_FOREACH( char ch, hello )
{
std::cout << ch;
}
return 0;
}
Upvotes: 2
Views: 4628
Reputation: 146910
You can't make a macro perform a command after a loop unless you put the loop in the macro. And seriously? It would be a much better idea just to make a scoped variable.
template<typename T> class CallFunctionOnScopeExit {
T t;
public:
CallFunctionOnScopeExit(T tt) : t(tt) {}
~CallFunctionOnScopeExit() { t(); }
};
Guaranteed in the cases of exception, etc, whereas the macro version most definitely isn't. I would prefer to use this pattern for the exception guarantees, and because it's more flexible than just copying the int.
Upvotes: 0
Reputation: 355049
The cleanest way to do this is probably to use an RAII container to reset the value:
// Assumes T's assignment does not throw
template <typename T> struct ResetValue
{
ResetValue(T& o, T v) : object_(o), value_(v) { }
~ResetValue() { object_ = value_; }
T& object_;
T value_;
};
used as:
{
ResetValue<int> resetter(xyz, 123);
// ...
}
When the block ends, the destructor will be called, resetting the object to the specified value.
If you really want to use a macro, as long as it is a relatively simple expression, you can do this using a for-block:
for (bool b = false; b == false; b = true, (xyz = 123))
{
// ...
}
which can be turned into a macro:
#define DO_AFTER_BLOCK(expr) \
for (bool DO_AFTER_BLOCK_FLAG = false; \
DO_AFTER_BLOCK_FLAG == false; \
DO_AFTER_BLOCK_FLAG = true, (expr))
used as:
DO_AFTER_BLOCK(xyz = 123)
{
// ...
}
I don't really think the macro approach is a good idea; I'd probably find it confusing were I to see this in production source code.
Upvotes: 8
Reputation: 753665
You don't absolutely need a macro - you could use inner scope variables:
#include <stdio.h>
int main(void)
{
int xyz = 123;
printf("xyz = %d\n", xyz);
{
int pqr = xyz;
int xyz = pqr;
printf("xyz = %d\n", xyz);
xyz++;
if (xyz < 1000)
xyz = 1;
printf("xyz = %d\n", xyz);
}
printf("xyz = %d\n", xyz);
return(0);
}
This produces the output:
xyz = 123
xyz = 123
xyz = 1
xyz = 123
If you compile with GCC and -Wshadow
you get a warning; otherwise, it compiles clean.
You can't write int xyz = xyz;
in the inner block reliably; once the '=' is parsed, the declaration is complete and so the initializer is the inner 'xyz', not the outer. The two step dance works, though.
The primary demerit of this is that it requires a modification in the code block.
If there are side-effects in the block - like the print statements above - you could call a function that contains the inner block. If there are no side-effects in the block, why are you executing it at all.
#include <stdio.h>
static void inner(int xyz)
{
printf("xyz = %d\n", xyz);
xyz++;
if (xyz < 1000)
xyz = 1;
printf("xyz = %d\n", xyz);
}
int main(void)
{
int xyz = 123;
printf("xyz = %d\n", xyz);
inner(xyz);
printf("xyz = %d\n", xyz);
return(0);
}
Upvotes: 2