C++ 如何消除代码中的重复?
作为概念验证的一部分,我正在尝试构建可用于构建GLSL脚本的代码。我首先做的事情之一是创建对GLSL类型的引用,并创建了一个系统,在该系统中,我可以根据枚举(GLSL数据类型的类型)查询在GLSL代码中表示它的字符串文字。下面是它的样子:C++ 如何消除代码中的重复?,c++,reflection,enums,C++,Reflection,Enums,作为概念验证的一部分,我正在尝试构建可用于构建GLSL脚本的代码。我首先做的事情之一是创建对GLSL类型的引用,并创建了一个系统,在该系统中,我可以根据枚举(GLSL数据类型的类型)查询在GLSL代码中表示它的字符串文字。下面是它的样子: #define VEC_EXPAND(name) g ## name ## 2, g ## name ## 3, g ## name ## 4 #define MAT_EXPAND(name) VEC_EXPAND(name), VEC_EXPAND(name
#define VEC_EXPAND(name) g ## name ## 2, g ## name ## 3, g ## name ## 4
#define MAT_EXPAND(name) VEC_EXPAND(name), VEC_EXPAND(name ## 2x), VEC_EXPAND(name ## 3x), VEC_EXPAND(name ## 4x)
enum class gtype : uint32_t {
gvoid,
gbool, gint, guint, gfloat, gdouble,
VEC_EXPAND(bvec), VEC_EXPAND(ivec), VEC_EXPAND(uvec), VEC_EXPAND(vec), VEC_EXPAND(dvec),
MAT_EXPAND(mat), MAT_EXPAND(dmat),
gsampler2d
};
#undef VEC_EXPAND
#undef MAT_EXPAND
#define GLSL_EXPAND(name) #name
#define VEC_EXPAND(name) GLSL_EXPAND(name ## 2), GLSL_EXPAND(name ## 3), GLSL_EXPAND(name ## 4)
#define MAT_EXPAND(name) VEC_EXPAND(name), VEC_EXPAND(name ## 2x), VEC_EXPAND(name ## 3x), VEC_EXPAND(name ## 4x)
template<class T, class... Tail, class Elem = typename std::decay<T>::type>
constexpr std::array<Elem, 1 + sizeof...(Tail)> make_array(T&& head, Tail&&... values)
{
return { std::forward<T>(head), std::forward<Tail>(values)... };
}
constexpr auto glsl_string_array = make_array(
"void", "bool", "int", "uint", "float", "double",
VEC_EXPAND(bvec), VEC_EXPAND(ivec), VEC_EXPAND(uvec), VEC_EXPAND(vec), VEC_EXPAND(dvec),
MAT_EXPAND(mat), MAT_EXPAND(dmat),
"sampler2d"
);
constexpr const char * to_string_literal(gtype type) {
return glsl_string_array[uint32_t(type)];
}
std::string to_string(gtype type) {
return to_string_literal(type);
}
#undef GLSL_EXPAND
#undef VEC_EXPAND
#undef MAT_EXPAND
#定义VEC#u扩展(name)g##name#2,g##name#3,g##name#4
#定义MAT#U EXPAND(名称)、VEC#U EXPAND(名称##2x)、VEC#U EXPAND(名称##3x)、VEC#U EXPAND(名称##4x)
枚举类G类型:uint32\u t{
gvoid,
gbool,gint,guint,gfloat,gdouble,
向量扩展(bvec)、向量扩展(ivec)、向量扩展(uvec)、向量扩展(VEC)、向量扩展(dvec),
MAT_扩展(MAT),MAT_扩展(dmat),
gsampler2d
};
#未定义向量扩展
#未定义的MAT_扩展
#定义GLSL_扩展(名称)#名称
#定义VEC#u EXPAND(名称)GLSL#u EXPAND(名称#2)、GLSL#u EXPAND(名称#3)、GLSL#u EXPAND(名称#4)
#定义MAT#U EXPAND(名称)、VEC#U EXPAND(名称##2x)、VEC#U EXPAND(名称##3x)、VEC#U EXPAND(名称##4x)
模板
constexpr std::数组生成数组(T&&head,Tail&&value)
{
返回{std::forward(head),std::forward(values)…};
}
constexpr auto glsl_string_array=make_array(
“无效”、“布尔”、“整数”、“单位”、“浮动”、“双精度”,
向量扩展(bvec)、向量扩展(ivec)、向量扩展(uvec)、向量扩展(VEC)、向量扩展(dvec),
MAT_扩展(MAT),MAT_扩展(dmat),
“采样器2D”
);
constexpr const char*到字符串文字(gtype类型){
返回glsl_字符串_数组[uint32_t(类型)];
}
std::字符串到_字符串(gtype类型){
返回_字符串_文本(类型);
}
#未定义GLSL_展开
#未定义向量扩展
#未定义的MAT_扩展
到目前为止,我对代码的功能没有任何问题,但是我将类型定义为枚举,然后将它们作为字符串文本再次写入的代码的重复对我来说肯定是个麻烦。我还必须添加更多类型(这不是唯一的GLSL类型!),我想为编写OpenCL内核代码编写类似的代码(这将取决于类似的语义),那么我如何减少这些代码,使每种类型只需要一个声明
此外,如果有任何建议可以减少甚至消除我对宏的使用,我将不胜感激。我不知道这是否适合您的情况,但我可以提出如下建议:
// things.inc
#ifndef GTYPE_VOID
#define GTYPE_VOID GTYPE_DECL(gvoid)
#endif
GTYPE_VOID
#undef GTYPE_VOID
#ifndef GTYPE_INT
#define GTYPE_INT GTYPE_DECL(gint)
#endif
GTYPE_INT
#undef GTYPE_INT
#ifndef GTYPE_FLOAT
#define GTYPE_FLOAT GTYPE_DECL(gfloat)
#endif
GTYPE_FLOAT
#undef GTYPE_FLOAT
然后,您可以按照自己喜欢的方式定义宏,并将其包含在需要的地方:
// things.cpp
enum class gtypes {
#define GTYPE_DECL(Thing) Thing,
#include "things.inc"
#undef GTYPE_DECL
};
const char *as_string(gtype t) {
switch (t) {
#define GTYPE_DECL(Thing) case gtype::Thing: return #Thing;
#include "things.inc"
#undef GTYPE_DECL
}
// or unreachable
return "(unknown)";
}
此外,您还可以尝试使用constexpr映射。我将不得不根据自己的需要对其进行调整,但我会对其进行测试,看看是否有效。