在C ++中编译时间生成的块 [英] Compile time generated block in C++
问题描述
我有一个结构体在我的服务器,我想生成它与宏或模板在C + +,因为它有很多多余的事情:
I have a struct in my server that I would like to generate it with macro or template in C++ as it has a lot of redundant things:
struct MyBlock {
void Merge(const MyBlock& from) {
if (apple.HasData()) {
apple.Merge(from.apple);
}
if (banana.HasData()) {
banana.Merge(from.banana());
}
...
}
void Clear() {
apple.Clear();
banana.Clear();
...
}
void Update(const SimpleBlock& simple_block) {
if (simple_block.apple.Updated()) {
apple.Add(simple_block.apple);
}
if (simple_block.banana.Updated()) {
banana.Add(simple_block.banana);
}
...
}
Fruit apple;
Fruit banana;
Animal dog;
Animal cat;
...
}
struct SimpleBlock {
SimpleFruit apple;
SimpleFruit banana;
SimpleAnimal dog;
SimpleAnimal cat;
...;
}
我想在两个块中定义更多的变量,如apple和dog。我也想定义更多的这样的块对。但它涉及很多微不足道的工作。所以我的问题是我们如何使用宏,模板或一些其他C ++功能,包括C ++ 11在编译时生成这些块?
I would like to define more variables in the two blocks like apple and dog. I would also like to define more pairs of such blocks. But it involves a lot of trivial work. So my question is how we can use macro, template or some other C++ features including C++11 to generate these blocks in compile time?
t使用集合来存储这些变量是因为MyBlock结构将作为参数在另一个模板类中传递,这将在运行时动态分配和释放此块。
The reason why I don't use collections to store those variable is because MyBlock struct would be passed as a parameter in another template class which would dynamically allocate and release this block in run time. It is actually a thread local block that would be aggregated periodically.
推荐答案
直接使用预处理器列表迭代:
Straightforward enough with preprocessor list iteration:
#define M_NARGS(...) M_NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define M_NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
#define M_CONC(A, B) M_CONC_(A, B)
#define M_CONC_(A, B) A##B
#define M_ID(...) __VA_ARGS__
#define M_LEFT(L, R) L
#define M_RIGHT(L, R) R
#define M_FOR_EACH(ACTN, ...) M_CONC(M_FOR_EACH_, M_NARGS(__VA_ARGS__)) (ACTN, __VA_ARGS__)
#define M_FOR_EACH_0(ACTN, E) E
#define M_FOR_EACH_1(ACTN, E) ACTN(E)
#define M_FOR_EACH_2(ACTN, E, ...) ACTN(E) M_FOR_EACH_1(ACTN, __VA_ARGS__)
#define M_FOR_EACH_3(ACTN, E, ...) ACTN(E) M_FOR_EACH_2(ACTN, __VA_ARGS__)
#define M_FOR_EACH_4(ACTN, E, ...) ACTN(E) M_FOR_EACH_3(ACTN, __VA_ARGS__)
#define M_FOR_EACH_5(ACTN, E, ...) ACTN(E) M_FOR_EACH_4(ACTN, __VA_ARGS__)
//.. extend this to higher numbers with some copy&paste
#define MYBLOCK(...) struct MyBlock { \
void Merge(const MyBlock& from) { \
M_FOR_EACH(BLOCK_MERGE, __VA_ARGS__) \
} \
void Clear() { \
M_FOR_EACH(BLOCK_CLEAR, __VA_ARGS__) \
} \
void Update(const SimpleBlock& simple_block) { \
M_FOR_EACH(BLOCK_UPDATE, __VA_ARGS__) \
} \
M_FOR_EACH(BLOCK_FIELD, __VA_ARGS__) \
}
#define BLOCK_MERGE(F) if (M_ID(M_RIGHT F).HasData()) { \
M_ID(M_RIGHT F).Merge(from.M_ID(M_RIGHT F)); \
}
#define BLOCK_CLEAR(F) M_ID(M_RIGHT F).Clear;
#define BLOCK_UPDATE(F) if (simple_block.M_ID(M_RIGHT F).Updated()) { \
M_ID(M_RIGHT F).Add(simple_block.M_ID(M_RIGHT F)); \
}
#define BLOCK_FIELD(F) M_ID(M_LEFT F) M_ID(M_RIGHT F);
#define SIMPLEBLOCK(...) struct SimpleBlock { M_FOR_EACH(SIMPLE_DECL, __VA_ARGS__) }
#define SIMPLE_DECL(F) M_CONC(Simple, M_ID(M_LEFT F)) M_ID(M_RIGHT F);
#define FIELDS (Fruit, apple),(Fruit,banana),(Animal,dog),(Animal,cat)
MYBLOCK(FIELDS);
SIMPLEBLOCK(FIELDS);
将必要的其他成员变量添加到 FIELDS
并且它们将被添加到由 MYBLOCK
和 SIMPLEBLOCK
发出的结构体中。 (记住用更多的迭代来扩展 M_FOR_EACH
...使用几个ctrl + c,ctrl + v可以很容易地扩展)
Add the necessary further member variables to FIELDS
in the existing format, and they will be added to the structs emitted by MYBLOCK
and SIMPLEBLOCK
. (Remember to extend M_FOR_EACH
with more iterations... easy to to with a few ctrl+c,ctrl+v.)
这篇关于在C ++中编译时间生成的块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!