Exactly, macro is not necessary for programming languages. For example, Java works quite fine without macro. Usually macro makes code more clear and shorter, at the same time, more dangerous.
So, what's the best way to use macro? Let's talk in code.
Exactly, macro is not necessary for programming languages. For example, Java works quite fine without macro. Usually macro makes code more clear and shorter, at the same time, more dangerous.
So, what's the best way to use macro? Let's talk in code.
With macro, you can write a beautiful solution for problem such as this:
Suppose, you want to define an enum called period whose members are one, five, ten, fifteen and thirty. Then here is how you do it:
First create a header file called period_items.h as:
//period_items.h
//Here goes the items of the enum
//it is not a definition in itself!
E(one)
E(five)
E(ten)
E(fifteen)
E(thirty)
then create another header file called period.h as:
//period.h
#include <string>
//HERE goes the enum definition!
enum period
{
#define E(item) item,
#include "period_items.h" //it dumps the enum items in here!
#undef E
period_end
};
period to_period(std::string const & name)
{
#define E(item) if(name == #item) return item;
#include "period_items.h"
#undef E
return period_end;
}
Now you can simply include period.h and use to_period function. :-)
You could also add this function to period.h as:
std::string to_string(period value)
{
#define E(item) if(value == item) return #item;
#include "period_items.h"
#undef E
return "<error>";
}
Now, you could write this:
#include "period.h"
period v = to_period("fifteen"); //string to period
std::string s = to_string(v); //period to string
Why this solution is beautiful?
Because now if you want to add few more members to the enum, all you have to do is to add them to period_items.h as:
//period_items.h
//Here goes the items of the enum
//it is not a definition in itself!
E(one)
E(five)
E(ten)
E(fifteen)
E(thirty)
E(fifty) //added item!
E(hundred) //added item!
E(thousand) //added item!
And you're done. to_string and to_period will work just fine, without any modification!
--
I took this solution from my solution to another problem, posted here:
I think the best way is to use inline
You get all the benefits of macro + all compile time checks
The primary thing macro is useful in c++ is for controlling the compilation. Something like:
#ifdef DEBUG:
//print some debug information
#endif
or
#ifdef OS_WINDOWS
//windows specific code
#
In my very personal opinion, a good macro is a very rare thing. I try to aviod them as much as possible, because most of them are more like a time bomb.
To be good, a macro must:
#define MACRO } someCode {, which sucks)I use macros only in places where nothing else works.
One example is having an easy mapping from error values to strings, for example instead of
switch(code) {
case ERR_OK: return "ERR_OK";
case ERR_FOO: return "ERR_FOO";
:
I use a simple macro like
#define CASE_STR(x) case x: return #x
so I can simplify this to
switch(code) {
CASE_STR(ERR_OK);
CASE_STR(ERR_FOO);
:
However, those cases are usually more for debugging.
Also, I've written a GLSL (OpenGL Shading Language) loop unrolling once using the boost preprocessor suite, which then could be used something like
const char *shader = "#version 120\n"
"..."
GLSL_UNROLL_FOR("int i",0,10,\
"foo += i\n" \
)
"...";
Here is an example (maintainable easily).
enum id {
#define ITEM(id, s) id,
# include "foo.itm"
#undef ITEM
nbItem
};
static char const *const s[] = {
#define ITEM(id, s) s,
# include "foo.itm
#undef ITEM
}