C++ C/C++;宏从类型的定义中定义类型
我想在另一个定义中展开一个定义,如下所示:C++ C/C++;宏从类型的定义中定义类型,c++,c,macros,C++,C,Macros,我想在另一个定义中展开一个定义,如下所示: #define SCALAR_TYPES uint8_t, int8_t, uint16_t, int16_t, double, string #define VECTOR_TYPES vector<uint8_t>, vector<int8_t>, vector<uint16_t>, vector<int16_t>, vector<double>, vector<string>
#define SCALAR_TYPES uint8_t, int8_t, uint16_t, int16_t, double, string
#define VECTOR_TYPES vector<uint8_t>, vector<int8_t>, vector<uint16_t>, vector<int16_t>, vector<double>, vector<string>
#define VARIANT_TYPENAMES SCALAR_TYPES, VECTOR_TYPES
extern "C"{
int getter_for_int(const char *key);
void put_for_intt(const char * key, int val);
void put_for_int_array(const char * key, int *val, uint32_t size);
}
这些只是其中的一小部分,但所有这些getter和put er的实现在不同的数据类型之间非常相似,如果我能让预处理器在#define中展开宏,那么这些函数可以由预处理器生成。您的问题不完整,因为包含的宏正在工作:
#包括
#定义标量类型uint8、int8、uint16、int16、双精度、字符串
#定义向量类型向量,向量,向量,向量,向量,向量,向量
#定义变量类型名称标量类型、向量类型
#定义STR(X)字符串化(X)
#定义STRINGIFY(X)#X
int main()
{
std::cout您的问题不完整,因为包含的宏正在工作:
#包括
#定义标量类型uint8、int8、uint16、int16、双精度、字符串
#定义向量类型向量,向量,向量,向量,向量,向量,向量
#定义变量类型名称标量类型、向量类型
#定义STR(X)字符串化(X)
#定义STRINGIFY(X)#X
int main()
{
std::cout如果您不介意巴洛克式语法,您可以使用。创建标量和向量类型的两个单独列表:
#define SCALAR_TYPES(_) \
_(u32, uint32_t) \
_(double, double) \
_(cstr, char *)
#define VECTOR_TYPES(_) \
_(u32, uint32_t) \
_(double, double) \
_(cstr, char *)
这两个宏是“gerenator MACROSS”。它们将另一个宏\uuuu
作为参数。该宏必须具有两个参数,用于创建合适的函数名的名称和描述标量类型或数组元素类型的类型
要在示例中创建接口,请首先创建所需的宏:
#define SCALAR_GET(N, T) T get_##N(const char *key);
#define VECTOR_GET(N, T) T *get_##N##_array(const char *key);
#define SCALAR_PUT(N, T) void put_##N(const char * key, T val);
#define VECTOR_PUT(N, T) void put_##N##_array(const char * key, T *val, uint32_t size);
然后将它们传递给两个生成器宏:
extern "C"{
SCALAR_TYPES(SCALAR_GET)
SCALAR_TYPES(SCALAR_PUT)
VECTOR_TYPES(VECTOR_GET)
VECTOR_TYPES(VECTOR_PUT)
}
这将产生:
extern "C" {
uint32_t get_u32(const char *key);
double get_double(const char *key);
char *get_cstr(const char *key);
void put_u32(const char *key, uint32_t val);
void put_double(const char *key, double val);
void put_cstr(const char *key, char *val);
uint32_t *get_u32_array(const char *key);
double *get_double_array(const char *key);
char **get_cstr_array(const char *key);
void put_u32_array(const char *key, uint32_t * val, uint32_t size);
void put_double_array(const char *key, double *val, uint32_t size);
void put_cstr_array(const char *key, char **val, uint32_t size);
}
要获取std::variant
的列表,请使用:
#define SCALAR_COMMA(N, T) T,
#define VECTOR_COMMA(N, T) T *,
#define VARIANT_TYPENAMES \
SCALAR_TYPES(SCALAR_COMMA) VECTOR_TYPES(VECTOR_COMMA)
但是有一个障碍:VARIANT\u typenames
将产生一个尾随逗号。在数组初始值设定项中,尾随逗号是允许的。在enum
s中,您可以在最后一个枚举值之后定义一个“max”值
但在文章的结尾,也有一个宏观的解决方案
还可以在gererator宏中包含数据的“类”——标量或向量&ndash
#define TYPES(_) \
_(SCALAR, u32, uint32_t) \
_(SCALAR, double, double) \
_(SCALAR, cstr, char *) \
_(VECTOR, u32_array, uint32_t) \
_(VECTOR, double_array, double) \
_(VECTOR, cstr_array, char *)
它们定义了一组以标量
或`向量`为前缀的宏,以便您可以通过标记粘贴来创建它们的名称:
#define SCALAR_TYPE(T) T
#define VECTOR_TYPE(T) T *
#define SCALAR_ARG(T) T val
#define VECTOR_ARG(T) T* val, uint32_t size
现在你的MARO看起来像:
#define GET(C, N, T) C##_TYPE(T) get_##N(const char *key);
#define PUT(C, N, T) void put_##N(const char * key, C##_ARG(T));
extern "C"{
TYPES(GET)
TYPES(PUT)
}
#define COMMA(C, N, T) C##_TYPE(T),
#define VARIANT_TYPENAMES TYPES(COMMA)
它们产生与上述相同的结果
最后,关于VARIANT_TYPENAMES
中的尾随逗号:您可以通过将每个宏中的尾随逗号转换为前导逗号,然后丢弃开头的逗号来去除逗号
#define COMMA(C, N, T) , C##_TYPE(T)
#define TAIL_(A, ...) __VA_ARGS__
#define TAIL(...) TAIL_(__VA_ARGS__)
#define VARIANT_TYPENAMES TAIL(TYPES(COMMA))
这是可行的,因为宏参数可以为空,但需要两步扩展才能将TAIL(类型(逗号))
转换为TAIL(,T1,T2,T3,…)
这个解决方案需要一些时间才能开始工作,特别是因为扩展宏的空格收缩,可读性不强,但是一旦有了系统,就可以轻松地添加新类型
使用宏的常见注意事项适用。我还想向您指出另一种可能的解决方案:编写脚本或程序,根据比X宏更好的定义为您生成接口,并将其包含在构建过程中。如果您不介意巴洛克语法,您可以使用。创建两个单独的标量和向量类型列表:
#define SCALAR_TYPES(_) \
_(u32, uint32_t) \
_(double, double) \
_(cstr, char *)
#define VECTOR_TYPES(_) \
_(u32, uint32_t) \
_(double, double) \
_(cstr, char *)
这两个宏是“gerenator MACROSS”。它们将另一个宏\uuuu
作为参数。该宏必须具有两个参数,用于创建合适的函数名的名称和描述标量类型或数组元素类型的类型
要在示例中创建接口,请首先创建所需的宏:
#define SCALAR_GET(N, T) T get_##N(const char *key);
#define VECTOR_GET(N, T) T *get_##N##_array(const char *key);
#define SCALAR_PUT(N, T) void put_##N(const char * key, T val);
#define VECTOR_PUT(N, T) void put_##N##_array(const char * key, T *val, uint32_t size);
然后将它们传递给两个生成器宏:
extern "C"{
SCALAR_TYPES(SCALAR_GET)
SCALAR_TYPES(SCALAR_PUT)
VECTOR_TYPES(VECTOR_GET)
VECTOR_TYPES(VECTOR_PUT)
}
这将产生:
extern "C" {
uint32_t get_u32(const char *key);
double get_double(const char *key);
char *get_cstr(const char *key);
void put_u32(const char *key, uint32_t val);
void put_double(const char *key, double val);
void put_cstr(const char *key, char *val);
uint32_t *get_u32_array(const char *key);
double *get_double_array(const char *key);
char **get_cstr_array(const char *key);
void put_u32_array(const char *key, uint32_t * val, uint32_t size);
void put_double_array(const char *key, double *val, uint32_t size);
void put_cstr_array(const char *key, char **val, uint32_t size);
}
要获取std::variant
的列表,请使用:
#define SCALAR_COMMA(N, T) T,
#define VECTOR_COMMA(N, T) T *,
#define VARIANT_TYPENAMES \
SCALAR_TYPES(SCALAR_COMMA) VECTOR_TYPES(VECTOR_COMMA)
但是有一个障碍:VARIANT\u typenames
将产生一个尾随逗号。在数组初始值设定项中,尾随逗号是允许的。在enum
s中,您可以在最后一个枚举值之后定义一个“max”值
但在文章的结尾,也有一个宏观的解决方案
还可以在gererator宏中包含数据的“类”——标量或向量&ndash
#define TYPES(_) \
_(SCALAR, u32, uint32_t) \
_(SCALAR, double, double) \
_(SCALAR, cstr, char *) \
_(VECTOR, u32_array, uint32_t) \
_(VECTOR, double_array, double) \
_(VECTOR, cstr_array, char *)
它们定义了一组以标量
或`向量`为前缀的宏,以便您可以通过标记粘贴来创建它们的名称:
#define SCALAR_TYPE(T) T
#define VECTOR_TYPE(T) T *
#define SCALAR_ARG(T) T val
#define VECTOR_ARG(T) T* val, uint32_t size
现在你的MARO看起来像:
#define GET(C, N, T) C##_TYPE(T) get_##N(const char *key);
#define PUT(C, N, T) void put_##N(const char * key, C##_ARG(T));
extern "C"{
TYPES(GET)
TYPES(PUT)
}
#define COMMA(C, N, T) C##_TYPE(T),
#define VARIANT_TYPENAMES TYPES(COMMA)
它们产生与上述相同的结果
最后,关于VARIANT_TYPENAMES
中的尾随逗号:您可以通过将每个宏中的尾随逗号转换为前导逗号,然后丢弃开头的逗号来去除逗号
#define COMMA(C, N, T) , C##_TYPE(T)
#define TAIL_(A, ...) __VA_ARGS__
#define TAIL(...) TAIL_(__VA_ARGS__)
#define VARIANT_TYPENAMES TAIL(TYPES(COMMA))
这是可行的,因为宏参数可以为空,但需要两步扩展才能将TAIL(类型(逗号))
转换为TAIL(,T1,T2,T3,…)
这个解决方案需要一些时间才能开始工作,特别是因为扩展宏的空格收缩,可读性不强,但是一旦有了系统,就可以轻松地添加新类型
使用宏的常见注意事项也适用。我还想向您指出另一种可能的解决方案:编写脚本或程序,根据比X宏更好的定义为您生成接口,并将其包含在构建过程中。不要使用宏。这似乎是std::variant
或类似的类型列表,所以可以使用简单的TyPulf:<代码>使用MyValue= STD::<代码> > <代码>定义EVAL(x)x??但是,您已经在“代码> vector < /CODE >中使用模板。如果您想要C++代码的C API(包在<代码>外)C“{< /代码>和<代码> } /代码>)然后你被限制在C中可用的类型。仅供参考:也许你应该编辑你的问题以显示宏应该如何使用。目前还不清楚——对我来说,