0

我正在尝试做类似的事情:

custommacro x;

这将扩展为:

declareSomething; int x; declareOtherthing;

这甚至可能吗?

我已经用过一次operator=这样的行为来欺骗它,但它不能用声明来完成。

4

3 回答 3

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

原因:

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

如果您想为此类命令创建一个完整的域特定语言,您还可以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;
}

在这种形式中,每个命令都预先设计为关闭前面的命令,因此只有最后一个需要done; 您需要begin一行,以便有一个打开命令来关闭第一个实际操作,否则括号将不匹配。

在 C 中这样搞砸比在 C++ 中要容易得多,因为 C 的预处理器更强大(它支持__VA_ARGS__对于复杂的宏元编程非常重要的功能)。

哦,是的,还有一件事——

...请不要在实际代码中这样做。

于 2013-04-28T17:52:22.130 回答
2

我了解您要做什么,但根本无法完成。宏只是文本替换,它不知道后面会发生什么,所以尝试做custommacro x将扩展到任何custommacro内容,一个空格,然后x,这在语义上不起作用。

此外,关于您的echohack:在 C++ 中使用运算符实际上非常简单:

#include <iostream>

#define echo std::cout <<

int main()
{
    echo "Hello World!";
}

但是您真的不应该编写这样的代码(即使用宏和伪回声 hack)。您应该编写符合语言语法和您正在尝试执行的操作的语义的代码。如果要写入标准输出,请使用std::cout. 此外,如果您想使用,请创建一个内部调用echo的函数,但不要破解该语言的功能来创建您自己的功能。echostd::cout

于 2013-04-14T13:02:41.393 回答
1

您可以使用 for 循环和 GnuC 语句表达式扩展。

#define MY_MACRO\
  FOR_MACRO(_uniq##__COUNTER__##name,{/*declareSomething*/ },{ /* declareOtherthing */ }) int

#define FOR_MACRO(NAME,FST_BLOCK,SND_BLOCK)\
  for(int NAME = ({FST_BLOCK ;0;}); NAME<1 ; NAME++,(SND_BLOCK))

它“实际上是卫生的”,尽管这意味着您在这些代码块中所做的任何事情都不会逃脱 for 循环范围。

于 2015-08-21T05:00:37.063 回答