假设我有一个类需要一些常量才能运行。几个成员函数需要使用这些常量。使用#define是不受欢迎的,因为它可能导致冲突。常量是8位或16位的十六进制模式,存储为uint8_t或uint16_t。这些常量也不会从类的实例更改为实例,因此只需要一个常量副本就可以保存内存(尽管内存非常少)。
是否有任何不正确的,或者更好的方式来实现上述目标,而不是简单地做以下事情:
// mycode.h
// .......
class myclass {
private:
static const uint16_t kMyClassConstant_ = 0xBEEF;
// .......
};
提前感谢您的帮助。
答案 0 :(得分:44)
鉴于您对情况的描述,我认为使用static const
成员是一种很好的方法。在C ++ 11中,您可能希望将其更改为static constexpr
以强调它是一个编译时常量,但不会因此而有效地改变。
如果您在代码中的某个地方以{one}定义规则(odr)的相关方式引用myclass::kMyClassContant_
,请参阅。在需要引用(包括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位)可能更好。
答案 1 :(得分:5)
您可以使用类型特征来实现此目的:
#include <type_traits>
class myclass {
private:
typedef std::integral_constant<uint16_t , 0xBEEF> kMyClassConstant;
// ...
};
用作myclass::kMyClassConstant::value
。
这显示了实现整数常量的目的,并防止您意外地获取常量的地址。
答案 2 :(得分:4)
自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
数据成员。