假设我有一个magic number
,我想摆脱...
//whatever.cpp
for (int i = 0; i < 42; i++)
{
//...
}
合理地,我可以通过两种方式杀死它:
在源文件中使用const int SOMETHING_SOMETHING_MEANING_OF_LIFE = 42
或constexpr int SOMETHING_SOMETHING_MEANING_OF_LIFE = 42
.cpp
。
在这种情况下,两者之间是否有任何有意义的区别(我记得编译器推断 - 在任何一种情况下 - 值都不会改变,因此42
实际上是在生成的循环/展开循环/任何机器代码中硬编码的)还是归结为个人品味?
在一个相关的问题中:如果magic number
(以及替换它的东西)是在头(.h
)文件中声明的,而不是源(.ccp
)文件,该怎么办 - 这会改变事情吗(如果是这样,如何)?
const int
只有在常量表达式初始化时才能用作常量表达式的一部分,但它不能保证它是常量表达式的一部分。
const int i = 42; // OK, usable in a constant expression
int j = 42;
const int k = j; // OK, not usable in a constant expression
constexpr int
保证变量的初始值设定项是常量表达式,否则程序将无法编译。
constexpr int i = 42; // OK, usable in a constant expression
int j = 42;
constexpr int k = j; // Compile-time error, 'j' is not a constant expression
因此,如果要确保初始值设定项确实是常量表达式,constexpr
是更好的选择。
两者之间是否有任何有意义的区别(我记得编译推断 - 在任何一种情况下 - 值都不会改变,并且实际上硬编码了生成的循环/展开循环/任何代码中的 42)还是归结为个人品味?
在您展示的情况下,代码生成不会有任何区别。
但是,不同之处在于constexpr
变量保证该值在编译时是已知的。参见维托里奥·罗密欧的回答。
出于文档目的,如果它确实是一个编译时值,那么编写constexpr
也是很好的:当有人阅读您的代码并看到constexpr
时,他们会自动知道这是一个真正的固定值。这在初始化不平凡的情况下很重要(例如,调用函数)。
您还可以看到constexpr
变量是包含文字的 C 宏的真正替代品(例如#define FOO 123
)。
最后,请记住,constexpr
意味着const
.
在一个相关的问题中:如果幻数(以及替换它的东西)是在头文件中而不是 .ccp 文件中声明的,这会改变事情吗?
不。但是,如果要在头文件中声明全局变量,则可能需要在constexpr
之上使用inline
(在 C++17 中可用),以便程序中只有一个实体,这是避免 ODR 问题并可能节省内存和初始化时间的优势。
有关详细信息,请参阅标头中的"const"和"constexpr"变量是否应该"内联"以防止违反 ODR?