技巧:使用宏填充数组值(代码生成)
我正在阅读上述主题,突然我想到了这个想法:为什么不尝试编写一些可以在我们的真实代码中使用的棘手的宏(而不仅仅是作为在现实生活中无用的谜题)?
所以我想到的第一件事是:用宏填充数组值:
int f(int &i) { return ++i; }
#define e100 r5(m20)
#define m20 m5,m5,m5,m5
#define m5 r5(e1)
#define e1 f(i) //avoiding ++i right here, to avoid UB!
#define r5(e) e,e,e,e,e
int main() {
int i=0; //this is used in the macro e1
int a[] = {e100}; //filling array values with macros!
int n = sizeof(a)/sizeof(int);
cout << "count = " << n << endl;
for(int i = 0 ; i < n ; i++ )
cout << a[i] << endl;
return 0;
}
输出:
count = 100
1
2
3
4
.
.
.
100
在线演示:http://www.ideone.com/nUYrq ideone.com/nUYrq
我们能否在紧凑性或通用性(可能两者兼而有之)方面进一步改进这个解决方案?我们可以去掉宏中需要的变量i
吗?或者有其他改进吗?
我还想知道这在 C++ 和 C 中是否都是有效的代码(当然忽略打印部分)?
编辑:
我意识到对 f()
的调用顺序似乎仍然未指定。但我不确定,因为我认为数组初始化中的逗号不可能与逗号运算符相同(通常)。但如果是的话,我们可以避免它吗?标准的哪一部分说它未指定?
Are C++ Templates just Macros in disguise?
I was reading the above topic, and suddenly this idea came to my mind: why not try writing some tricky macros which can be used in our real code, (not just only as puzzles which are useless in real life)?
So the first thing came to mind is : filling array values with macros:
int f(int &i) { return ++i; }
#define e100 r5(m20)
#define m20 m5,m5,m5,m5
#define m5 r5(e1)
#define e1 f(i) //avoiding ++i right here, to avoid UB!
#define r5(e) e,e,e,e,e
int main() {
int i=0; //this is used in the macro e1
int a[] = {e100}; //filling array values with macros!
int n = sizeof(a)/sizeof(int);
cout << "count = " << n << endl;
for(int i = 0 ; i < n ; i++ )
cout << a[i] << endl;
return 0;
}
Output:
count = 100
1
2
3
4
.
.
.
100
Online demo : http://www.ideone.com/nUYrq
Can we further improve this solution in terms of compactness or genericity (possibly both)? Can we get rid of the variable i
which we need in the macro? Or any other improvement?
I would also like to know if that is valid code both in C++ and C (of course ignoring printing part)?
EDIT:
I realized that the order of calls to f()
seems still unspecified. I'm not sure though, as I think comma in array initialization is not probably same as comma operator (in general). But if it is, can we avoid it and what part of the Standard says its unspecified?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果您想深入研究预处理器编程,我只能推荐 Boost。预处理器库作为构建块,您将避免从头开始重写。
例如,为了创建您的表格,我会使用 (ideone):
并将所有麻烦留给 Boost :)
注意:这枚举从 0 到 99,而不是 1 到 100,还有其他可用于执行算术的操作;)
编辑: 这是如何工作的?
首先,我只能推荐 BOOST_PP_ENUM 的文档条目
BOOST_PP_ENUM
是一个宏,它有 3 个参数:(n, MACRO, data)
n
:一个整数MACRO
:接受 3 个参数的宏:(z, i, data)
data
:为方便起见,将传递给(z, i, data)
的一些数据code>macro然后它将被 n 次连续的
MACRO
调用所取代,并以逗号分隔:您可以对
MACRO
执行任何您想要的操作。恐怕我从未使用过 z 参数,它是在内部使用的,理论上你可以使用它来加速该过程。
If you wish to delve into Preprocessor programming, I can only recommend the Boost.Preprocessor library as a building block, you'll avoid having to rewrite things from scratch.
For example, in order to create your table, I would have used (ideone):
And leave all the cruft to Boost :)
Note: this enumerates from 0 to 99, not 1 to 100, there are other operations available to perform arithmetic ;)
EDIT: How does this work ?
First, I can only recommend the doc entry for BOOST_PP_ENUM
BOOST_PP_ENUM
is a macro which takes 3 arguments:(n, MACRO, data)
n
: an integerMACRO
: a macro accepting 3 arguments:(z, i, data)
data
: some data, of your convenience, to be passed tomacro
It will then be replaced by n successive invocations of
MACRO
separated by commas:It is up to you to do whatever you wish with your
MACRO
.I am afraid I have never used the
z
argument, it is used internally, and you could in theory use it to speed up the process.P99 有一个宏可以完全满足您的需求
它的优点是它完全是编译时间,无需使用函数进行动态初始化等根本不。
对于您来说,它可能有一个缺点,即它使用 C99 功能,特别是具有可变长度参数的宏。
P99 has a macro that does exactly what you want
It has the advantage that it is entirely compile time, no dynamic initialization with functions etc at all.
For you, it probably has the disadvantage that it uses C99 features, in particular macros with variable length arguments.
不,这不是有效的代码;该行为仍然未定义。由于数组初始化元素之间没有序列点,因此对 f() 的调用可以按任何顺序发生。
可以生成序列。 Boost.Preprocessor 就是这样做的,并使用这样的序列来发出更有趣的东西。
No, this is not valid code; the behaviour is still undefined. Since there are no sequence points between array-initialisation elements, the calls to f() may occur in any order.
It is possible to generate sequences. Boost.Preprocessor does so, and uses such sequences to emit much more interesting stuff.
我认为
template
仍将提供卓越的解决方案,该解决方案将是明确的且不易出错。看下面的代码;许多事情仅在编译时计算,它应该生成高效的代码。乍一看可能有点复杂,但可以理解。它仍然可以变得更通用。用法如下简单:
这可以用于任何
int a[N]
。这是代码的输出。I think still the
template
would provide superior solution which will be definite and less error prone. See the following code; many of things are calculated at compile time only and it should generate efficient code.It might be little complex at first glance, but understandable. It can be still made more general. Usage will be as simple as following:
This can be used for any
int a[N]
. Here is the output of the code.一些简单的代码生成怎么样?
然后使用它:
生成代码: http://www.ideone.com/iQjrj
使用代码: http://ideone.com/SQikz
How about some simple code generation.
Then putting it to use:
Generating the code: http://www.ideone.com/iQjrj
Using the code: http://ideone.com/SQikz