英文:
How to create a lookup table from list of constants with a macro?
问题
我想创建一个查找表,将常量值映射到常量名称。
struct char TABLE[128][32] = { [CONST_1] = "CONST_1", [CONST_2] = "CONST_2", ... };
我为此定义了两个宏。
#define TBL(N, S, ...) static char N[S][1 << 5] = { __VA_ARGS__ };
#define V(T) [T] = #T
这样,我可以这样定义我的表格。
TBL(CODES, LastExtensionError,
V(Success), V(BadRequest), V(BadValue), ...);
是否可以避免将每个常量用 V
包装,而像这样写?
TBL(CODES, LastExtensionError,
Success, BadRequest, BadValue, ...);
英文:
I want to create a lookup up table from a constant value to a constant name
struct char TABLE[128][32] = { [CONST_1] = "CONST_1",[CONST_2] = "CONST_2", ... };
I defined two macros for that
#define TBL(N, S, ...) static char N[S][1 << 5] = { __VA_ARGS__ };
#define V(T) [T] = #T
So I can define my table like that,
TBL (CODES, LastExtensionError,
V (Success), V (BadRequest), V (BadValue), ... );
Is it possible to avoid wrapping each constant with V
and write something like?
TBL (CODES, LastExtensionError,
Success, BadRequest, BadValue, ...);
答案1
得分: 2
> 是否有可能避免用 V 包装每个常数并写类似这样的代码?
这是C预处理器,无论如何,您必须枚举所有可能的迭代。您可以编写一个foreach宏并将其应用于每个元素。
我看不到在宏后面隐藏一个简单的 static char N[S][1 << 5] =
的价值。只需写 static char CODES[LastExtensionError][1 << 5] =
。如果您确实想要重复 [1 << 5]
,考虑制作一个结构。
#define FOREACH_1(f, _1) f(_1)
#define FOREACH_2(f, _1, ...) f(_1) FOREACH_1(f, VA_ARGS)
#define FOREACH_3(f, _1, ...) f(_1) FOREACH_2(f, VA_ARGS)
#define FOREACH_4(f, _1, ...) f(_1) FOREACH_3(f, VA_ARGS)
#define FOREACH_5(f, _1, ...) f(_1) FOREACH_4(f, VA_ARGS)
/* 等等。根据需要添加更多情况 */
#define FOREACH_N(_5,_4,_3,_2,_1,N,...) FOREACH##N
#define FOREACH(f, ...) FOREACH_N(VA_ARGS,_5,_4,_3,2,_1)(f, VA_ARGS)
#define TBL_FOREACH_CB(a) [a] = #a,
#define TBL_INIT(...) { FOREACH(TBL_FOREACH_CB, VA_ARGS) }
static char CODES[LastExtensionError][1 << 5] = TBL_INIT(
Success,
BadRequest,
BadValue
)
如果您不想自己编写代码,可以使用诸如 BOOST_PP_FOR
或 P99_FOR
的库。
此外,这样写成 static char CODES[N][1<<5]
似乎有些奇怪,而不是像 static const char *const CODES[N]
。奇怪的是值是可变的,并且所有字符串都有恒定的长度,听起来像是浪费了内存。
英文:
> Is it possible to avoid wrapping each constant with V and write something like?
This is C preprocessor, one way or the other you have to enumerate all possible iterations. You can write a foreach macro and apply it on each element.
I see no value in hiding a simple static char N[S][1 << 5] =
behind a macro. Just write static char CODES[LastExtensionError][1 << 5] =
. If you do want to repeat [1 << 5]
, consider making a structure.
#define FOREACH_1(f, _1) f(_1)
#define FOREACH_2(f, _1, ...) f(_1) FOREACH_1(f, __VA_ARGS__)
#define FOREACH_3(f, _1, ...) f(_1) FOREACH_2(f, __VA_ARGS__)
#define FOREACH_4(f, _1, ...) f(_1) FOREACH_3(f, __VA_ARGS__)
#define FOREACH_5(f, _1, ...) f(_1) FOREACH_4(f, __VA_ARGS__)
/* etc. add more cases as many as you need */
#define FOREACH_N(_5,_4,_3,_2,_1,N,...) FOREACH##N
#define FOREACH(f, ...) FOREACH_N(__VA_ARGS__,_5,_4,_3,_2_,_1)(f, __VA_ARGS__)
#define TBL_FOREACH_CB(a) [a] = #a,
#define TBL_INIT(...) { FOREACH(TBL_FOREACH_CB, __VA_ARGS__) }
static char CODES[LastExtensionError][1 << 5] = TBL_INIT(
Success,
BadRequest,
BadValue
)
You could use a library like BOOST_PP_FOR
or P99_FOR
if you do not want to write it yourself.
Also, it sounds odd that this is static char CODES[N][1<<5]
and not like static const char *const CODES[N]
. It's odd that values are mutable, and all strings have constant length, sounds like wasted memory.
答案2
得分: 1
这是一个随着行数呈指数级增长的解决方案:
#define CM__0(P,f,...) CM_P1(CM_P1(CM_P1(CM_P1(CM_P1(CM_##f(,P##__VA_ARGS__))))))
#define CM__1(P,f,...) CM_P2(CM_P2(CM_P2(CM_P2(CM_P2(CM_##f(,P##__VA_ARGS__))))))
#define CM__2(P,f,...) CM_P3(CM_P3(CM_P3(CM_P3(CM_P3(CM_##f(,P##__VA_ARGS__))))))
#define CM__3(P,f,...) CM_P4(CM_P4(CM_P4(CM_P4(CM_P4(CM_##f(,P##__VA_ARGS__))))))
#define CM__4(P,f,...) CM_##f(,P##__VA_ARGS__)
#define CM_P1(x) CM__1 x
#define CM_P2(x) CM__2 x
#define CM_P3(x) CM__3 x
#define CM_P4(x) CM__4 x
#define CM_SCAN(...) __VA_ARGS__
#define CM_EAT(...)
#define CM_LPAREN (
#define CM(...) CM_SCAN(CM_EAT CM_LPAREN CM__0(__VA_ARGS__))
#define TUPLE_AT_1(a,b,...) b
#define CHECK(...) TUPLE_AT_1(__VA_ARGS__,)
#define TBL_0end_0end ,TBL_END
#define CM_0tbl(P,x,...) CHECK(TBL_0end_##x, TBL_NEXT)(,x,P##__VA_ARGS__)
#define TBL_END(...) )
#define TBL_NEXT(P,x,...) (,0tbl,P##__VA_ARGS__) [x] = #x,
#define TBL(...) CM(,0tbl,__VA_ARGS__,0end)
struct char TABLE[128][32] = {
TBL(CONST_1, CONST_2, CONST_3)
// [CONST_3] = "CONST_3", [CONST_2] = "CONST_2", [CONST_1] = "CONST_1",
};
如果您需要进一步的解释或帮助,请随时提出。
英文:
Here is a solution that scales exponentially with the number of lines:
// supports 782 iterations ((5^n + 3)/4)
#define CM__0(P,f,...) CM_P1(CM_P1(CM_P1(CM_P1(CM_P1(CM_##f(,P##__VA_ARGS__))))))
#define CM__1(P,f,...) CM_P2(CM_P2(CM_P2(CM_P2(CM_P2(CM_##f(,P##__VA_ARGS__))))))
#define CM__2(P,f,...) CM_P3(CM_P3(CM_P3(CM_P3(CM_P3(CM_##f(,P##__VA_ARGS__))))))
#define CM__3(P,f,...) CM_P4(CM_P4(CM_P4(CM_P4(CM_P4(CM_##f(,P##__VA_ARGS__))))))
#define CM__4(P,f,...) CM_##f(,P##__VA_ARGS__)
#define CM_P1(x) CM__1 x
#define CM_P2(x) CM__2 x
#define CM_P3(x) CM__3 x
#define CM_P4(x) CM__4 x
#define CM_SCAN(...) __VA_ARGS__
#define CM_EAT(...)
#define CM_LPAREN (
#define CM(...) CM_SCAN(CM_EAT CM_LPAREN CM__0(__VA_ARGS__))
#define TUPLE_AT_1(a,b,...) b
#define CHECK(...) TUPLE_AT_1(__VA_ARGS__,)
#define TBL_0end_0end ,TBL_END
#define CM_0tbl(P,x,...) CHECK(TBL_0end_##x, TBL_NEXT)(,x,P##__VA_ARGS__)
#define TBL_END(...) )
#define TBL_NEXT(P,x,...) (,0tbl,P##__VA_ARGS__) [x] = #x,
#define TBL(...) CM(,0tbl,__VA_ARGS__,0end)
struct char TABLE[128][32] = {
TBL(CONST_1, CONST_2, CONST_3)
// [CONST_3] = "CONST_3", [CONST_2] = "CONST_2", [CONST_1] = "CONST_1",
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论