29

假设我有一个需要一些常量才能运行的类。几个成员函数需要使用这些常量。不赞成使用#define,因为它会导致冲突。常量是 8 位或 16 位的十六进制模式,存储为 uint8_t 或 uint16_t。这些常量也不会因类的实例而改变,因此只需保存一份常量副本即可节省内存(尽管内存很少)。

有什么不合适的,或者可能有更好的方法来完成上述操作,而不是简单地执行以下操作:

// mycode.h
// .......
class myclass {
private:
  static const uint16_t kMyClassConstant_ = 0xBEEF;
// .......
};

在此先感谢您的帮助。

4

3 回答 3

47

鉴于您对情况的描述,我会说使用static const成员是一种好方法。在 C++11 中,您可能希望将其更改为static constexpr以强调它是编译时常量,尽管不会因此而有效地改变任何内容。

如果您以myclass::kMyClassContant_在单一定义规则 (odr) 下相关的方式引用代码中的某处,尤其是。在需要引用(包括 const-reference)的上下文中,编译器会抱怨没有定义常量。在这种情况下,仅仅在类中声明和初始化它是不够的。这可能会迫使您将声明和定义分开:

// mycode.h
class myclass {
private:
  static const uint16_t kMyClassConstant_;
};

// mycode.cpp
const uint16_t myclass::kMyClassConstant_ = 0xBEEF;

为了避免维护单独的声明和定义的麻烦,有些人更喜欢声明内联 constexpr 函数而不是实际变量:

// mycode.h
class myclass {
private:
  static constexpr uint16_t kMyClassConstant_()
  { return 0xBEEF; }
};

对于许多与 odr 相关的问题,这是一种正确的解决方法,并且不会导致任何性能损失。它是否真的有用取决于维护普通静态常量的单独声明和定义的负担有多大。如果您希望常量永远不会随着代码的发展而改变,那么最好使用具有单独定义的普通静态常量。但是,如果您经常修改常量的定义,则必须重新编译定义文件并将其重新链接到项目的所有相关部分可能会使您认为上述基于函数的解决方案是更好的选择。

关于数据类型的最后评论:std::uint16_t如果您需要以紧凑的形式存储大量这些值,则使用强制将其转换为 16 位可能很有用。否则,实际大小可能并不重要,在这种情况下std::uint_fast16_t(可能大于 16 位)可能会更好。

于 2013-06-12T03:12:44.023 回答
5

您可以使用类型特征来实现这一点:

#include <type_traits>

class myclass {
private:
  typedef std::integral_constant<uint16_t , 0xBEEF> kMyClassConstant;

  // ...
};

用作myclass::kMyClassConstant::value.

这显示了实现整数常量的目的,并防止您意外获取常量的地址。

于 2013-06-12T07:09:15.293 回答
5

从 C++17 开始,我们可以访问inline变量,这些变量负责处理与 odr 相关的问题。几个选项:

// mycode.h
class myclass {
    static const inline uint16_t kMyClassConstant_ = 0xBEEF;
};

或者,如果它可以被标记constexpr(就像在这种情况下):

// mycode.h
class myclass {
    static constexpr inline uint16_t kMyClassConstant_ = 0xBEEF;
};

可以简化为:

// mycode.h
class myclass {
    static constexpr uint16_t kMyClassConstant_ = 0xBEEF;
};

因为在 C++17 中constexpr意味着inline数据static成员。

于 2018-07-05T07:02:17.240 回答