【问题标题】:Where to define class constants in C++?在 C++ 中哪里定义类常量?
【发布时间】:2019-12-02 10:41:26
【问题描述】:

在 C++ 中,为了拥有更整洁的代码,我想在我的头文件中将一组值声明为常量,例如:

constexpr float SIZE_SMALL = 1.5f; 
constexpr float SIZE_MEDIUM = 2.5f; 
constexpr std::string COLOR_RED = "RED"; 
constexpr std::string MATERIAL_SILK = "SILK";
...etc

但这变得太长且笨拙。此外,一些常量可以组合在一起,因为它们描述了同一属性的不同值,例如SIZE_SMALLSIZE_MEDIUM

在我的头文件中写这个最好的方法是什么?我考虑了结构,例如

struct SIZE
{
float SMALL; 
float MEDIUM; 
}

但是我必须在我的 .cpp 中声明和定义一个变量,这有点超出了所有这一切的目的。

【问题讨论】:

  • 您能解释一下“但这太长而且太笨拙了”吗?我不一定会明白为什么。我会按语义对这些常量进行分组,最终将它们放入嵌套命名空间namespace size { constexpr float small = 1.5f; }
  • static constexpr 成员变量呢?
  • @YSC,我在同一个命名空间中有大约 50 多个这样的常量
  • 好吧,你知道命名空间是免费的。
  • 哦,你的意思是命名空间中的命名空间?听起来不错

标签: c++ header refactoring constants compile-time-constant


【解决方案1】:

然后我必须在我的 .cpp 中声明和定义一个变量,这有点超出了所有这些的目的。

不,你不知道。您可以将字段设置为 staticconstexpr

struct SIZES {
    static constexpr const float SMALL = 1.5f;
};

但是,我建议不要这样做。不仅您不必创建此类的实例,而且您也不应该创建此类的实例(为什么?)。那么为什么首先要使用类呢?改用namespaces 对常量进行分组:

namespace SIZES {
    constexpr float SMALL = 1.5f; 
}

我在同一个命名空间中有大约 50 多个这样的常量

除非你找到一种方法让编译器读懂你的想法,否则你必须把它们全部写下来。说真的,这可以被压缩的唯一方法是这些常量之间是否存在某种关系,例如SMALL + 1.0f = MEDIUM,但这在您的问题中并不明显。

【讨论】:

  • 可以用于命名空间 (y)。但是,如果我定义一个结构体 - 带有静态和 constexpr 字段 - 而不声明一个实例,我将如何在代码中使用该结构体?
  • @FakherMokadem static 成员的意义在于您不需要需要实例来访问它们...
  • @FakherMokadem SIZES::SMALL,顺便说一句,我只是建议您不要使用结构的静态 const 成员...
  • @foreknownas_463035818:我认为您不需要在constexpr 旁边添加const。对于变量,constexpr 也是const。它在 Scott Meyers 的 Effective Modern C++ 中被提及。
  • @ConstantinosGlynos 我不确定它是否有任何效果,但我仍然喜欢在那里。至少它对还不熟悉constexpr 的人有影响。这在多大程度上有意义,取决于谁会阅读您的代码(对我来说确实如此)
【解决方案2】:

这取决于您的实际使用情况,但 consider using proper strong types 而不是基本类型。例如,要声明大小,请将它们的类型设为 size,而不是 float。这并直接解决了您的分组问题,但它为您提供了强类型的所有其他好处,并且还可能有助于分组:

struct size {
private: float value;
public:
    explicit constexpr size(float value) : value{value} {}
    explicit constexpr operator float() const noexcept { return value; }
};

namespace default_sizes {
    constexpr auto SMALL = size{1.5f};
    constexpr auto MEDIUM = size{2.5f};
    // …
}

事实上,对于特定领域的使用,除了非常有限的情况外,我一般会避免使用裸基本类型,并始终将它们封装在自己的特定领域类型中。

【讨论】:

  • 是否可以用除整数以外的任何东西来启动枚举?
  • @FakherMokadem 是的,you can use non-ints as the underlying type,但它们仍然需要是整数类型。请注意,我没有说“使用枚举”(因为你不能),我建议“模仿一个枚举”。
猜你喜欢
  • 2011-01-03
  • 1970-01-01
  • 2012-08-31
  • 2021-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多