When could macro make code more beautiful than function does? [closed]

旧巷老猫 提交于 2020-02-25 08:44:09

问题


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.


回答1:


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" \
)
"...";



回答2:


With macro, you can write a beautiful solution for problem such as this:

  • Define an enum such that its value can be converted into its string representation and vice-versa.

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:

  • converting from enum to int



回答3:


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
#



回答4:


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:

  • Be simple.
  • Never ever be ambiguous
  • Never brake the code structure (I've seen macros like #define MACRO } someCode {, which sucks)
  • Be unable to throw an exception, or something like that, basically, it must never make debugging harder
  • Have a name that explains the meaning clearly
  • There must be a really good reason to use a macro instead of, say, an inline function, like compilation control, or header guarding.



回答5:


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
}


来源:https://stackoverflow.com/questions/11685706/when-could-macro-make-code-more-beautiful-than-function-does

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!