简体   繁体   English

如何摆脱此代码中的重复项?

[英]How can I get rid of the duplication in this code?

As part of a Proof of Concept, I'm trying to trying to build code that I can use to build GLSL scripts. 作为概念验证的一部分,我正在尝试构建可用于构建GLSL脚本的代码。 One of the first things I've done is create references to the GLSL types, and created a system where I can query, based on an enum (which is the type of the GLSL data type) the string-literal that represents it in GLSL code. 我要做的第一件事就是创建对GLSL类型的引用,并创建一个系统,供我查询,该系统基于枚举(这是GLSL数据类型的类型)在GLSL中表示它的字符串字面量码。 Here's what it looks like: 看起来是这样的:

#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

So far, I've had no problems with the functionality of the code, but that duplication of the code where I define the types as an enum, and then write them again as a string literal is definitely troubling to me. 到目前为止,我对代码的功能没有任何问题,但是重复的代码将我定义为枚举的类型,然后再次将它们写为字符串文字,这确实困扰着我。 I'm going to have to add more types as well (these are hardly the only GLSL types!) and I would like to write similar code for writing OpenCL Kernel code (which will depend on similar semantics), so how can I reduce this code down so that I only need one declaration of each type? 我还将不得不添加更多类型(这些几乎不是唯一的GLSL类型!),并且我想编写类似的代码来编写OpenCL内核代码(这将取决于类似的语义),所以我该如何减少它代码下来,以便我只需要每个类型的一个声明?

Also, any advice which would reduce or even eliminate my use of Macros would be appreciated. 此外,任何会减少甚至消除我对宏的使用的建议都将受到赞赏。

I don't know whether this fits your case, but I can suggest something like: 我不知道这是否适合您的情况,但是我可以建议如下:

// 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

You can then define the macro in the way you like, and include it in places where you need: 然后,您可以按照自己喜欢的方式定义宏,并将其包含在需要的地方:

// 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)";
}

Also, you can try to use a constexpr map. 另外,您可以尝试使用constexpr映射。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM