我正在尝试做类似的事情:
custommacro x;
这将扩展为:
declareSomething; int x; declareOtherthing;
这甚至可能吗?
我已经用过一次operator=
这样的行为来欺骗它,但它不能用声明来完成。
我正在尝试做类似的事情:
custommacro x;
这将扩展为:
declareSomething; int x; declareOtherthing;
这甚至可能吗?
我已经用过一次operator=
这样的行为来欺骗它,但它不能用声明来完成。
只要您愿意接受两个添加,就可以省略括号:
例如:
#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;
)
...
原因:
done
,比如宏,它将扩展为包含必要关闭括号的表单echo ... done
表单看起来不像是对预处理器的宏调用,所以当预处理器进入它时,它没有被标记为展开,我们是否放入括号是无关紧要的。因此,仅使用echo ... done
将在文本中转储 ECHO_MACRO 调用DSL
)包装整个块将导致对 ECHO_MACRO 的调用在此重新扫描时被扩展通过(DSL
对结果没有任何作用:它的存在只是为了强制重新扫描)(
的扩展中的,否则宏体中不匹配的括号会混淆预处理器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;
}
在这种形式中,每个命令都预先设计为关闭前面的命令,因此只有最后一个需要done
; 您需要begin
一行,以便有一个打开命令来关闭第一个实际操作,否则括号将不匹配。
在 C 中这样搞砸比在 C++ 中要容易得多,因为 C 的预处理器更强大(它支持__VA_ARGS__
对于复杂的宏元编程非常重要的功能)。
哦,是的,还有一件事——
...请不要在实际代码中这样做。
我了解您要做什么,但根本无法完成。宏只是文本替换,它不知道后面会发生什么,所以尝试做custommacro x
将扩展到任何custommacro
内容,一个空格,然后x
,这在语义上不起作用。
此外,关于您的echo
hack:在 C++ 中使用运算符实际上非常简单:
#include <iostream>
#define echo std::cout <<
int main()
{
echo "Hello World!";
}
但是您真的不应该编写这样的代码(即使用宏和伪回声 hack)。您应该编写符合语言语法和您正在尝试执行的操作的语义的代码。如果要写入标准输出,请使用std::cout
. 此外,如果您想使用,请创建一个内部调用echo
的函数,但不要破解该语言的功能来创建您自己的功能。echo
std::cout
您可以使用 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 循环范围。