C++使用类/结构体实现独立命名空间常量如何避免构造代码重复
最优实现方案
完全不需要重复编写两次构造逻辑,可按优先级选择以下方案:
方案1:直接将现有构造函数改造为constexpr(首选)
C++20起已经支持constexpr动态内存分配、constexpr异常抛出(编译期触发的异常会直接报编译错误),且glm从0.9.9.8版本开始也提供了完整的constexpr运算支持,仅需做少量改造即可:
- 先确认环境依赖满足要求:
- 编译标准指定为C++20及以上
- 升级glm到0.9.9.8及以上版本,同时定义
GLM_FORCE_CONSTEXPR宏开启constexpr支持
- 给现有构造函数加上
constexpr修饰符,内部逻辑完全不需要修改,同时建议把原代码的指针成员改为值存储,避免野指针和内存泄漏问题:
struct ColorspaceData { private: glm::vec3 sMatrix; public: /// X red float xr; /// Y red float yr; /// Z red float zr; /// X green float xg; /// Y green float yg; /// Z green float zg; /// X blue float xb; /// y blue float yb; /// Z blue float zb; /// Whitepoint WhitepointData whitepoint; /// A [3x3] matrix used in linear-gamma transformation function glm::mat3 linearTransform; /// Result of linear-gamma transformation function as `LinearTransformData` TransformData linearTransformData; constexpr ColorspaceData(float c_xr, float c_yr, float c_xg, float c_yg, float c_xb, float c_yb, StdIlluminant c_whitepoint, TransformData c_linearTransformData) : linearTransformData(std::move(c_linearTransformData)) { xr = c_xr / c_yr; xg = c_xg / c_yg; xb = c_xb / c_yb; yr = 1.0f; yg = 1.0f; yb = 1.0f; zr = (1.0f - c_xr - c_yr) / c_yr; zg = (1.0f - c_xg - c_yg) / c_yg; zb = (1.0f - c_xb - c_yb) / c_yb; switch (c_whitepoint) { case (StdIlluminant::A): whitepoint = WhitepointData(0.44757f, 0.40745f); break; case (StdIlluminant::B): whitepoint = WhitepointData(0.34842f, 0.35161f); break; case (StdIlluminant::C): whitepoint = WhitepointData(0.31006f, 0.31616f); break; case (StdIlluminant::D50): whitepoint = WhitepointData(0.34567f, 0.35850f); break; case (StdIlluminant::D55): whitepoint = WhitepointData(0.33242f, 0.34743f); break; case (StdIlluminant::D65): whitepoint = WhitepointData(0.31271f, 0.32902f); break; case (StdIlluminant::D75): whitepoint = WhitepointData(0.29902f, 0.31485f); break; case (StdIlluminant::D93): whitepoint = WhitepointData(0.28315f, 0.29711f); break; case (StdIlluminant::E): whitepoint = WhitepointData(0.33333f, 0.33333f); break; case (StdIlluminant::F1): whitepoint = WhitepointData(0.31310f, 0.33727f); break; case (StdIlluminant::F2): whitepoint = WhitepointData(0.37208f, 0.37529f); break; case (StdIlluminant::F3): whitepoint = WhitepointData(0.40910f, 0.39430f); break; case (StdIlluminant::F4): whitepoint = WhitepointData(0.44018f, 0.40329f); break; case (StdIlluminant::F5): whitepoint = WhitepointData(0.31379f, 0.34531f); break; case (StdIlluminant::F6): whitepoint = WhitepointData(0.37790f, 0.38835f); break; case (StdIlluminant::F7): whitepoint = WhitepointData(0.31292f, 0.32933f); break; case (StdIlluminant::F8): whitepoint = WhitepointData(0.34588f, 0.35875f); break; case (StdIlluminant::F9): whitepoint = WhitepointData(0.37417f, 0.37281f); break; case (StdIlluminant::F10): whitepoint = WhitepointData(0.34609f, 0.35986f); break; case (StdIlluminant::F11): whitepoint = WhitepointData(0.38052f, 0.37713f); break; case (StdIlluminant::F12): whitepoint = WhitepointData(0.43695f, 0.40441f); break; case (StdIlluminant::LEDB1): whitepoint = WhitepointData(0.4560f, 0.4078f); break; case (StdIlluminant::LEDB2): whitepoint = WhitepointData(0.4357f, 0.4012f); break; case (StdIlluminant::LEDB3): whitepoint = WhitepointData(0.3756f, 0.3723f); break; case (StdIlluminant::LEDB4): whitepoint = WhitepointData(0.3422f, 0.3502f); break; case (StdIlluminant::LEDB5): whitepoint = WhitepointData(0.3118f, 0.3236f); break; case (StdIlluminant::LEDBH1): whitepoint = WhitepointData(0.4474f, 0.4066f); break; case (StdIlluminant::LEDRGB1): whitepoint = WhitepointData(0.4557f, 0.4211f); break; case (StdIlluminant::LEDV1): whitepoint = WhitepointData(0.4560f, 0.4548f); break; case (StdIlluminant::LEDV2): whitepoint = WhitepointData(0.3781f, 0.3775f); break; case (StdIlluminant::Theatre): whitepoint = WhitepointData(0.3141f, 0.351f); break; default: throw ColorException("Undefined whitepoint value"); } sMatrix = glm::vec3(whitepoint.x, whitepoint.y, whitepoint.z) * glm::inverse(glm::mat3x3(xr, xg, xb, yr, yg, yb, zr, zg, zb)); linearTransform = glm::mat3(sMatrix[0] * xr, sMatrix[1] * xg, sMatrix[2] * xb, sMatrix[0] * yr, sMatrix[1] * yg, sMatrix[2] * yb, sMatrix[0] * zr, sMatrix[1] * zg, sMatrix[2] * zb); } };
- 直接声明编译期常量即可,完全不需要宏定义:
constexpr ColorspaceData ColorspaceDefaultSRGB{0.64f, 0.33f, 0.3f, 0.6f, 0.15f, 0.06f, StdIlluminant::D65, TransformData{1.055f, 0.0031308f, 12.0f / 5.0f, 12.92f, 0.04045f}};
方案2:抽离公共逻辑(适配C++17及更低版本)
如果暂时无法升级到C++20,可以把公共计算逻辑抽成constexpr静态函数,运行期和编译期构造函数都调用这组公共函数,不会产生代码重复:
- 抽离三原色参数计算逻辑为constexpr静态函数
- 抽离白点查询逻辑为constexpr静态函数
- 两个构造函数统一调用上述函数初始化成员变量
内容的提问来源于stack exchange,提问作者Wusiki Jeronii
相关产品推荐
相关产品推荐

