C++ 我们可以有递归宏吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12447557/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can we have recursive macros?
提问by user1367292
I want to know if we can have recursive macros in C/C++? If yes, please provide a sample example.
我想知道我们是否可以在 C/C++ 中使用递归宏?如果是,请提供示例。
Second thing: why am I not able to execute the below code? What is the mistake I am doing? Is it because of recursive macros?
第二件事:为什么我不能执行下面的代码?我在做什么错误?是因为递归宏吗?
# define pr(n) ((n==1)? 1 : pr(n-1))
void main ()
{
int a=5;
cout<<"result: "<< pr(5) <<endl;
getch();
}
采纳答案by verdesmarald
Your compiler probably provides an option to only pre-process, not actually compile. This is useful if you are trying to find a problem in a macro. For example using g++ -E
:
您的编译器可能只提供预处理选项,而不是实际编译选项。如果您试图在宏中查找问题,这将很有用。例如使用g++ -E
:
> g++ -E recursiveMacro.c
# 1 "recursiveMacro.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "recursiveMacro.c"
void main ()
{
int a=5;
cout<<"result: "<< ((5==1)? 1 : pr(5 -1)) <<endl;
getch();
}
As you can see, it is not recursive. pr(x)
is only replaced once during pre-processing. The important thing to remember is that all the pre-processor does is blindly replace one text string with another, it doesn't actually evaluate expressions like (x == 1)
.
如您所见,它不是递归的。pr(x)
仅在预处理期间更换一次。需要记住的重要一点是,预处理器所做的只是盲目地将一个文本字符串替换为另一个文本字符串,它实际上并不评估像(x == 1)
.
The reason your code will not compile is that pr(5 -1)
was not replaced by the pre-processor, so it ends up in the source as a call to an undefined function.
您的代码无法编译的原因是它pr(5 -1)
没有被预处理器替换,因此它最终在源代码中作为对未定义函数的调用。
回答by Paul Fultz II
Macros don't directly expand recursively, but there are workarounds. When the preprocessor scans and expands pr(5)
:
宏不会直接递归扩展,但有解决方法。当预处理器扫描和扩展时pr(5)
:
pr(5)
^
it creates a disabling context, so that when it sees pr
again:
它创建了一个禁用上下文,以便在它pr
再次看到时:
((5==1)? 1 : pr(5-1))
^
it becomes painted blue, and can no longer expand, no matter what we try. But we can prevent our macro from becoming painted blue by using deferred expressions and some indirection:
它变成蓝色,无论我们怎么尝试都无法再扩展。但是我们可以通过使用延迟表达式和一些间接来防止我们的宏变成蓝色:
# define EMPTY(...)
# define DEFER(...) __VA_ARGS__ EMPTY()
# define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)()
# define EXPAND(...) __VA_ARGS__
# define pr_id() pr
# define pr(n) ((n==1)? 1 : DEFER(pr_id)()(n-1))
So now it will expand like this:
所以现在它会像这样扩展:
pr(5) // Expands to ((5==1)? 1 : pr_id ()(5 -1))
Which is perfect, because pr
was never painted blue. We just need to apply another scan to make it expand further:
这是完美的,因为pr
从来没有被漆成蓝色。我们只需要应用另一个扫描以使其进一步扩展:
EXPAND(pr(5)) // Expands to ((5==1)? 1 : ((5 -1==1)? 1 : pr_id ()(5 -1 -1)))
We can apply two scans to make it expand further:
我们可以应用两次扫描使其进一步扩展:
EXPAND(EXPAND(pr(5))) // Expands to ((5==1)? 1 : ((5 -1==1)? 1 : ((5 -1 -1==1)? 1 : pr_id ()(5 -1 -1 -1))))
However, since there is no termination condition, we can never apply enough scans. I'm not sure what you want to accomplish, but if you are curious on how to create recursive macros, here is an example of how to create a recursive repeat macro.
然而,由于没有终止条件,我们永远无法应用足够的扫描。我不确定您想要完成什么,但如果您对如何创建递归宏感到好奇,这里有一个如何创建递归重复宏的示例。
First a macro to apply a lot of scans:
首先是一个应用大量扫描的宏:
#define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
#define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
#define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
#define EVAL5(...) __VA_ARGS__
Next, a concat macro which is useful for pattern matching:
接下来,一个对模式匹配很有用的 concat 宏:
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
Increment and decrement counters:
递增和递减计数器:
#define INC(x) PRIMITIVE_CAT(INC_, x)
#define INC_0 1
#define INC_1 2
#define INC_2 3
#define INC_3 4
#define INC_4 5
#define INC_5 6
#define INC_6 7
#define INC_7 8
#define INC_8 9
#define INC_9 9
#define DEC(x) PRIMITIVE_CAT(DEC_, x)
#define DEC_0 0
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define DEC_6 5
#define DEC_7 6
#define DEC_8 7
#define DEC_9 8
Some macros useful for conditionals:
一些对条件有用的宏:
#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x))
#define NOT_0 ~, 1,
#define COMPL(b) PRIMITIVE_CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0
#define BOOL(x) COMPL(NOT(x))
#define IIF(c) PRIMITIVE_CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t
#define IF(c) IIF(BOOL(c))
#define EAT(...)
#define EXPAND(...) __VA_ARGS__
#define WHEN(c) IF(c)(EXPAND, EAT)
Putting it all together we can create a repeat macro:
把它们放在一起,我们可以创建一个重复宏:
#define REPEAT(count, macro, ...) \
WHEN(count) \
( \
OBSTRUCT(REPEAT_INDIRECT) () \
( \
DEC(count), macro, __VA_ARGS__ \
) \
OBSTRUCT(macro) \
( \
DEC(count), __VA_ARGS__ \
) \
)
#define REPEAT_INDIRECT() REPEAT
//An example of using this macro
#define M(i, _) i
EVAL(REPEAT(8, M, ~)) // 0 1 2 3 4 5 6 7
So, yes with some workarounds you can have recursive macros in C/C++.
所以,是的,通过一些变通方法,您可以在 C/C++ 中使用递归宏。
回答by David Hammen
You're not supposedto have recursive macros in C or C++.
您不应该在 C 或 C++ 中使用递归宏。
The relevant language from the C++ standard, section 16.3.4 paragraph 2:
来自 C++ 标准的相关语言,第 16.3.4 节第 2 段:
If the name of the macro being replaced is found during this scan of the replacement list (not including the rest of the source file's preprocessing tokens), it is not replaced. Furthermore, if any nested replacements encounter the name of the macro being replaced, it is not replaced. These nonreplaced macro name preprocessing tokens are no longer available for further replacement even if they are later (re)examined in contexts in which that macro name preprocessing token would otherwise have been replaced.
如果在替换列表的这次扫描期间找到被替换的宏的名称(不包括源文件的其余预处理标记),则不会替换它。此外,如果任何嵌套替换遇到被替换的宏的名称,则不会替换它。这些未替换的宏名称预处理标记不再可用于进一步替换,即使稍后在宏名称预处理标记将被替换的上下文中(重新)检查它们。
There's some wiggle room in this language. With multiple macros that invoke one another, there's a grey area where that wording doesn't quite say what should be done. There is an active issue against the C++ standard regarding this language lawyer problem; see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#268.
这种语言有一些回旋余地。对于多个相互调用的宏,有一个灰色区域,其中的措辞并没有完全说明应该做什么。关于这个语言律师问题,有一个反对 C++ 标准的活跃问题;见http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#268。
Ignoring that language lawyer issue, every compiler vendor understands the intent:
忽略语言律师问题,每个编译器供应商都理解其意图:
Recursive macros are not allowed in C or in C++.
C 或 C++ 中不允许使用递归宏。
回答by Zdeslav Vojkovic
Most likely you are not able to execute it because you can't compile it. Also if it would compile correctly, it would always return 1. Did you mean (n==1)? 1 : n * pr(n-1)
.
您很可能无法执行它,因为您无法编译它。此外,如果它能够正确编译,它总是会返回 1。你的意思是(n==1)? 1 : n * pr(n-1)
.
Macros can't be recursive. According to chapter 16.3.4.2 (thanks Loki Astari), if the current macro is found in the replacement list, it is left as is, thus your pr
in the definition will not be changed:
宏不能递归。根据第 16.3.4.2 章(感谢 Loki Astari),如果在替换列表中找到当前宏,则保持原样,因此您pr
在定义中的定义不会改变:
If the name of the macro being replaced is found during this scan of the replacement list (not including the rest of the source file's pre- processing tokens), it is not replaced. Further, if any nested replacements encounter the name of the macro being replaced, it is not replaced. These nonreplaced macro name preprocessing tokens are no longer available for further replacement even if they are later (re)examined in contexts in which that macro name preprocessing token would otherwise have been replaced.
如果在替换列表的这次扫描期间找到被替换的宏的名称(不包括源文件的其余预处理标记),则不会替换它。此外,如果任何嵌套替换遇到被替换的宏的名称,则不会替换它。这些未替换的宏名称预处理标记不再可用于进一步替换,即使稍后在宏名称预处理标记将被替换的上下文中(重新)检查它们。
Your call:
您的来电:
cout<<"result: "<< pr(5) <<endl;
was converted by preprocessor into:
被预处理器转换为:
cout<<"result: "<< (5==1)? 1 : pr(5-1) <<endl;
During this, the definition of pr
macro is 'lost', and compiler shows an error like "‘pr' was not declared in this scope (fact)" because there is no function named pr
.
在此期间,pr
宏的定义“丢失”,编译器显示错误,如“未在此范围内声明‘pr’(事实)”,因为没有名为pr
.
Use of macros is not encouraged in C++. Why don't you just write a function?
在 C++ 中不鼓励使用宏。你为什么不写一个函数?
In this case you could even write a template function so it will be resolved in compile time, and will behave as a constant value:
在这种情况下,您甚至可以编写一个模板函数,以便在编译时解析它,并将表现为一个常量值:
template <int n>
int pr() { pr<n-1>(); }
template <>
int pr<1>() { return 1; }
回答by sth
You can't have recursive macros in C or C++.
在 C 或 C++ 中不能有递归宏。