消灭魔数: "const int" 和 "constexpr int" 有什么区别(或者最终没有区别)

14

假设我有一个想要除去的魔法数字...

//whatever.cpp

for (int i = 0; i < 42; i++)
{
    //...
}

我可以用两种方法来解决这个问题:

在源代码的.cpp文件中,可以使用const int SOMETHING_SOMETHING_MEANING_OF_LIFE = 42
或者使用constexpr int SOMETHING_SOMETHING_MEANING_OF_LIFE = 42

在这种情况下,这两种方法是否有任何有意义的区别(我记得编译器会推断出 - 无论使用哪种方法 - 值不会改变,因此在生成的循环/展开的循环/任何机器代码中,42实际上是硬编码的),还是只是个人口味的不同?

在一个相关的问题上:如果magic number(因此替换它的东西)在头文件(.h)中声明而不是在源文件(.ccp)中声明,那么这会改变什么(如果有的话,怎么改变)?


3
@出生时分配的唯一标识符 - 请在答案部分发布答案。谢谢。 - StoryTeller - Unslander Monica
5
@StoryTeller建议使用宏,我可以为此投反对票。 - Marek R
7
@MarekR - 是的,不规避该网站的同行评审系统是目的。 - StoryTeller - Unslander Monica
6
它们没有范围,可能会导致意外的构建问题,并可能对使用它们的表达式产生影响。它们没有明确定义的类型。它们属于C风格。 - Marek R
5
宏在C++代码中被严重不鼓励使用,这一点可以从以下权威来源得到证实:Bjarne Stroustrup自己的网站、isocpp和CppCoreGuidelines(社区努力)。请注意,所有这些链接都是来自权威来源。 - Tarick Welling
显示剩余3条评论
2个回答

20

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是更好的选择。

此外,它只能在初始化之后作为常量表达式使用。也就是说,如果您有一个没有初始化程序的前向声明,则即使定义稍后使用常量表达式进行初始化(直到该定义之后),它也不能用作常量表达式。 - eerorika
2
非常感谢您的出色回答 - 这是我希望能够接受两个答案的情况之一 叹气 - CharonX

14
在这种情况下,两者之间是否有任何有意义的区别(我记得编译器推断出在任何一种情况下都不会改变值,并且实际上在生成的循环/展开的循环/其他代码中硬编码了42),还是归结于个人喜好?
在您展示的情况下,代码生成没有任何区别。
但是,差异在于constexpr变量保证该值在编译时已知。请参见VittorioRomeo's answer
如果它确实是编译时值,则写入constexpr也是很好的文档目的:当某人阅读您的代码并看到constexpr时,他们自动知道它是一个真正固定的值。在初始化非平凡的情况下(例如调用函数),这一点至关重要。
您还可以将constexpr变量视为包含文字的C宏的真正替代品(例如#define FOO 123)。
最后,请记住constexpr意味着const。
相关问题:如果魔术数字(以及替换它的内容)在头文件而不是.ccp文件中声明,那会改变什么吗?
不需要。然而,如果您在头文件中声明全局变量,您可能希望在constexpr之上使用inline(C++17可用),以便在程序中只有一个实体,这是避免ODR问题和可能节省内存和初始化时间的优势。
请参见是否应在头文件中将`const`和`constexpr`变量设置为`inline`以防止ODR违规?获取更多信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接