技巧:使用宏填充数组值(代码生成)
Trick : filling array values using macros (code generation)
C++模板只是伪装的宏吗?
我正在阅读上面的主题,突然我想到了这个想法:为什么不试着写一些棘手的宏,这些宏可以在我们的真实代码中使用(不仅仅是作为在现实生活中无用的谜题(?
因此,首先想到的是:用宏填充数组值:
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
我们能在紧致性或泛型(可能两者都有(方面进一步改进这个解决方案吗?我们能去掉宏中需要的变量i
吗?或者还有其他改进吗?
我也想知道这是否是C++和C中的有效代码(当然忽略打印部分(?
编辑:
我意识到对f()
的调用顺序似乎仍然未指定。不过我不确定,因为我认为数组初始化中的逗号是而不是,可能与逗号运算符(通常(相同。但如果是,我们能避免吗?标准的哪一部分说它的未指明?
如果你想深入研究预处理器编程,我只能推荐Boost。预处理器库作为构建块,您将避免从头开始重写。
例如,为了创建您的表,我会使用(ideone(:
#include <iostream>
#include <boost/preprocessor/repetition/enum.hpp>
#define ORDER(z, n, text) n
int main() {
int const a[] = { BOOST_PP_ENUM(100, ORDER, ~) };
std::size_t const n = sizeof(a)/sizeof(int);
std::cout << "count = " << n << "n";
for(std::size_t i = 0 ; i != n ; ++i )
std::cout << a[i] << "n";
return 0;
}
把所有的麻烦都留给Boost:(
注意:此枚举范围为0到99,而不是1到100,还有其他操作可用于执行算术;(
编辑:这是如何工作的?
首先,我只能推荐BOOST _PP_ENUM 的文档条目
BOOST_PP_ENUM
是一个包含3个参数的宏:(n, MACRO, data)
n
:整数MACRO
:接受3个参数的宏:(z, i, data)
data
:为了方便起见,一些数据将传递给macro
然后,它将被MACRO
的n个连续调用所取代,用逗号分隔:
MACRO(z, 0, data), MACRO(z, 1, data), ... , MACRO(z, n-1, data)
这取决于你用你的MACRO
做任何你想做的事。
恐怕我从未使用过z
论点,它是在内部使用的,理论上你可以使用它来加快这个过程。
P99有一个宏,它可以执行您想要的
#include "p99_map.h"
int Ara[] = { P99_POSS(100) };
它的优点是完全是编译时的,完全没有函数等的动态初始化。
对您来说,它可能有一个缺点,即它使用C99功能,特别是具有可变长度参数的宏。
否,这不是有效的代码;这种行为仍不明确。由于数组初始化元素之间没有序列点,因此对f((的调用可以按任何顺序进行。
可以生成序列。促进预处理器这样做,并使用这样的序列来发出更有趣的东西。
我认为template
仍然会提供更出色的解决方案,它将是确定的,而且不容易出错。请参阅以下代码;很多东西都是在编译时计算的,它应该生成高效的代码。
template<int VALUE, int INDEX, int SIZE, bool ALLOW>
struct Assign
{
static void Element (int *p)
{
Assign<VALUE + 1, INDEX + 1, SIZE, (INDEX < SIZE)>::Element(p);
p[INDEX] = VALUE;
}
};
template<int VALUE, int INDEX, int SIZE>
struct Assign<VALUE, INDEX, SIZE, false>
{
static void Element (int *p) { p[INDEX] = VALUE; }
};
template<int START, int SIZE>
void Initialize (int (&a)[SIZE])
{
Assign<START, 0, SIZE, true>::Element(a);
}
乍一看可能有点复杂,但可以理解。它仍然可以变得更普遍。用法如下所示:
int a[100];
Initialize<1>(a); // '1' is the starting value
这可以用于任何int a[N]
。这是代码的输出。
简单的代码生成怎么样。
#include <fstream>
int main() {
std::ofstream fout("sequence_macros.hpp");
for(int i=1; i<=100; ++i)
{
fout << "#define e" << i << "(a) ";
fout << "(a+0)";
for(int j=1; j<i; ++j)
{
fout << ",(a+" << j << ")";
}
fout << 'n';
}
}
然后投入使用:
#include <iostream>
#include "sequence_macros.hpp"
int main()
{
// Create an array with 157 elements, in
// sequence, starting at 25
int x[] = {e100(25),e50(25+100),e7(25+100+50)};
int sz = sizeof(x) / sizeof(*x);
for(int i=0; i<sz; ++i)
std::cout << x[i] << 'n';
}
正在生成代码:http://www.ideone.com/iQjrj
使用代码:http://ideone.com/SQikz
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 在将数字随机生成为数组期间从内存输出随机数的数组
- 在C++中,如何初始化指向wchar_t*的指针数组(生成wchar_t**)
- C++如何生成std::数组列表
- 为什么我需要C++中不同的排序格式来对这个USACO代码上的数组和优先级队列进行排序
- 有没有一种代码密度较低的方法来使用非默认构造函数初始化数组?
- 请解释字谜的代码,我看不懂计数器数组,每个值已经是0
- 代码使用向量成功运行,但使用数组显示错误
- 查找自动生成键并具有线性内存消耗的小型关联数组
- 将随机生成的数字添加到数组 + 对这些数组求平均值
- G++ 发出警告,要求删除一个代码的数组,但不删除另一个代码的数组
- 在 c++ 代码中将数组传递给函数错误
- 尝试使用Huffman String代码更新数组
- 为什么在我的 mex 代码中将数组大小标识为零?
- 代码ARP数组,指针和内存分配(Windows IP功能)的不可理解的部分
- 在g++上进行聚合初始化的std::数组生成大量代码
- 将排序代码与数组合并,陷入合并,只需要一点点修正
- 将代码从数组移植到向量
- 在处理数组访问时可能会生成不一致的代码
- 技巧:使用宏填充数组值(代码生成)