宏观元编程恐怖

Tri*_* AI 0 c++ macros metaprogramming c-preprocessor

我想做的事情如下:

custommacro x;
Run Code Online (Sandbox Code Playgroud)

这将扩展为:

declareSomething; int x; declareOtherthing;
Run Code Online (Sandbox Code Playgroud)

这甚至可能吗?

我已经把它欺骗了一次,operator=表现得像那样,但它不能用声明来完成.

Leu*_*nko 6

只要您愿意接受两个补充,您就可以忽略括号:

  1. 整个代码需要包装在一个块宏中
  2. 在echo指令之后需要有一些东西

例如:

#define LPAREN (
#define echo ECHO_MACRO LPAREN
#define done )

#define ECHO_MACRO(X) std::cout << (X) << "\n"

#define DSL(X) X

...
DSL(
    echo "Look ma, no brains!" done;
)
...
Run Code Online (Sandbox Code Playgroud)

原因:

  1. 如果没有括号,就无法进行类似函数的宏扩展.这只是宏语言的基本要求; 如果你想要别的东西调查一个不同的宏处理器
  2. 因此,我们需要插入括号; 反过来,我们需要在指令之后有一些东西,比如一个done宏,它将扩展为包含必要的关闭表格的形式
  3. 不幸的是,因为echo ... done表单看起来不像是对预处理器的宏调用,所以当预处理器进入时它没有标记为扩展,并且我们是否将parens放入或不相关.echo ... done因此,只需使用将在文本中转储ECHO_MACRO调用
  4. 文本被重新扫描,标记为扩展,并且当它是类似函数宏的参数时再次展开,因此用块宏(此处为DSL)包裹整个块将导致在此重新扫描时扩展对ECHO_MACRO的调用传递(DSL不对结果做任何事情:它只是为了强制重新扫描而存在)
  5. 我们需要隐藏(在echo简单宏后面的扩展LPAREN,因为否则宏体中不匹配的括号会混淆预处理器

如果要为此类命令创建完整的特定于域的语言,还可以done通过使核心命令更加难以处理来减少命令数量:

#define LPAREN (

#define begin NO_OP LPAREN 0
#define done );

#define echo ); ECHO_MACRO LPAREN
#define write ); WRITE_MACRO LPAREN
#define add ); ADD_MACRO LPAREN
#define sub ); SUB_MACRO LPAREN

#define NO_OP(X) 
#define ECHO_MACRO(X) std::cout << (X) << "\n"
#define WRITE_MACRO(X) std::cout << (X)
#define ADD_MACRO(D, L, R) (D) = (L) + (R)
#define SUB_MACRO(D, L, R) (D) = (L) - (R)

#define DSL(X) DSL_2 X
#define DSL_2(X) X

int main(void) {
int a, b;
DSL((
    begin
      add a, 42, 47
      sub b, 64, 50
      write "a is:  "
      echo a
      write "b is:  "
      echo b
    done
))
return 0;
}
Run Code Online (Sandbox Code Playgroud)

在这种形式中,每个命令都预先设计为关闭前面的命令,因此只有最后一个命令需要一个done; 你需要一条begin线,这样就有一个打开的命令可以关闭第一个真正的操作,否则它们会不匹配.

在C语言中比在C++中更容易搞乱,因为C的预处理器更强大(它支持__VA_ARGS__哪些对于复杂的宏元编程非常重要).

哦是的,还有一件事 -

...请从来没有在真正的代码做到这一点.