C++ 技巧:使用宏填充数组值(代码生成)
我正在读上面的主题,突然想到了这个想法:为什么不试着编写一些可以在我们的真实代码中使用的复杂宏(不仅仅是在现实生活中无用的谜题) 所以首先想到的是:用宏填充数组值:C++ 技巧:使用宏填充数组值(代码生成),c++,c,arrays,macros,C++,C,Arrays,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 a
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;
}
在线演示:
我们能否在紧凑性或泛型性(可能两者兼而有之)方面进一步改进此解决方案?我们可以去掉宏中需要的变量i
?还是其他的改进
我想知道这是否是C++和C(当然忽略打印部分)的有效代码?< /P>
编辑:
我意识到调用
f()
的顺序似乎还没有确定。但我不确定,因为我认为数组初始化中的逗号可能与逗号运算符(通常)不同。但是如果是,我们能避免它吗?标准的哪一部分说它未指定?不,这是无效代码;这种行为还没有定义。由于数组初始化元素之间没有序列点,因此对f()的调用可以按任意顺序进行
可以生成序列。预处理器就是这样做的,并使用这样的序列来产生更多有趣的东西。简单的代码生成怎么样
#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';
}
}
#包括
int main(){
std::of stream fout(“sequence_macros.hpp”);
for(int i=1;i有一个宏,它可以完全满足您的需要
#include "p99_map.h"
int Ara[] = { P99_POSS(100) };
它的优点是完全是编译时的,没有函数的动态初始化等等
对于您来说,它可能有一个缺点,即它使用C99功能,特别是带有可变长度参数的宏。我认为模板将提供更优的解决方案,它将是明确的,并且不容易出错。请参阅以下代码;许多内容仅在编译时计算,并且应该生成高效的代码
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*p)
{
赋值::元素(p);
p[指数]=数值;
}
};
模板
结构分配
{
静态空元素(int*p){p[INDEX]=VALUE;}
};
模板
无效初始化(整型(&a)[大小])
{
赋值::元素(a);
}
乍一看可能有点复杂,但可以理解。它仍然可以变得更一般。用法如下所示:
int a[100];
Initialize<1>(a); // '1' is the starting value
inta[100];
初始化(a);//“1”是起始值
这可以用于任何inta[N]
。以下是.如果您希望深入研究预处理器编程,我只能建议将该库作为一个构建块,您将避免从头重写
例如,为了创建表,我会使用():
使用宏
,您可以随心所欲
恐怕我从来没有使用过z
参数,它是在内部使用的,理论上你可以使用它来加速过程。@Marcelo:是的。我在发布代码后意识到了这一点。但是任何改进,我们可以避免吗?@Nawaz:对不起,我意识到我的评论实际上是一个答案,所以我将其移动。@Downvoters:为什么是downvote?不是问一个问题,要求改进/纠正?@Nawaz-问题也可能不好。你为什么要发明一个宏来做什么,例如generate()
from can ready do?@Bo Persson:这个问题有什么不好的地方吗?我不能尝试一些我还不知道的东西吗?我不能以一种我以前从未尝试过的方式来探索这门语言吗?另外,我不知道generate()
可用于在初始化过程中填充数组。请给我举个例子。我认为它现在是“未指定”的,而不是“未定义的”。@ybungalobill:我没有时间调查,因此同意或不同意,但是的,听起来差不多。@Marcelo:我认为数组初始化中的逗号与逗号运算符(通常)不同。我可能错了。标准怎么说?@Marcelo:你能举一个生成序列的Boost.Preprocessor
的例子吗?它能填充数组值吗?@Nawaz:是的,逗号运算符不同于数组初始化中使用的逗号,但这两种用法都没有引入序列点。逗号运算符可以自由计算其参数按相反的顺序,只要它“返回”最后一个参数。这将需要多次编译和运行代码;我认为OP需要一个更简单的解决方案或增强功能。+1.我喜欢这个想法,它实际上是基于我已经实现的想法。而且,它使用不同的程序生成宏。它可以合并吗?@Nawaz,为了合并这2个;我们必须增强上面的程序,而ch将首先放置#define
,然后运行实际的可执行文件。@iammilind:到ideone的第二个链接是合并,但这不是我的意思。我的意思是,我们可以编写更少的宏来完成越来越多的不同类型的工作,因为@Benjamin的解决方案有太多的宏。它们没有太多的通用性。+1.太棒了。我们能自己编写这样的宏吗(对于C++)?它是如何编写的?@Nawaz,不幸的是,这绝非直截了当。你真的需要查看P99的细节。(或者在我的博客上了解一些解释)许多C++编译器都有变量作为扩展,所以它可以工作。如果你想使用模板,那么就不需要自己编写模板。你可以使用现有的一个:..但然后尝试1。@Nawaz,我觉得上面的模板解决方案将在编译时完成大部分工作,并将提供与,inta[100]={1,2,3,…,99};
几乎相同的效果(它将避免运行时i++
对较大数组的操作)。就数组而言,它在编译时不起任何作用。每个数组元素都有一个函数调用。@Nawaz,我的意思是针对我的模板解决方案;它将在编译时完成。但是,我不能保证,但我觉得编译器应该能够优化代码,并做出正确的选择
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
#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;
}
MACRO(z, 0, data), MACRO(z, 1, data), ... , MACRO(z, n-1, data)