为什么要将int声明为constexpr

5

在观看一个链接至isocpp.org的C++11教程视频时,我注意到了一些东西:

constexpr int windowWidth{800}, windowHeight{600};

声明这些 int 变量为 constexpr,而不仅仅是 const,有何意义?

1
可能是const vs constexpr on variables的重复问题。 - perreal
2个回答

6

很棒的视频Vittorio!

以下是声明 int constconstexpr 之间的区别摘要:

int get_int();  // Some run time function that returns int

template <int N>  // example use requiring a compile time int
struct test {};

const     int w = get_int();  // initialized at run time
const     int x = 5;          // initialized at compile time
constexpr int y = get_int();  // error, can not initialize at compile time
constexpr int z = 6;          // initialized at compile time

int
main()
{
    test<w> tw;  // error, w is not a compile time constant
    test<x> tx;  // ok, x is a compile time constant
    test<y> ty;  // error, there is no compile time constant named y
    test<z> tz;  // ok, z is a compile time constant
}

当你使用constexpr时,你要求初始化在编译时发生,否则会出现编译时错误。当你使用const时,你允许初始化在运行时发生,尽管如果初始化器本身是编译时常量,则仍然会在编译时发生。
如果你有一个const int,代码审查员必须查看初始化(如果这是const int的副本,则返回到原始值)以知道该const int是编译时常量还是运行时常量。
如果你有一个constexpr int,代码审查员可以立即假设它是编译时常量,而不需要分析它是如何初始化的。如果这个假设是错误的,编译器将标记它为错误。 <免责声明> 在下面的评论中,Kerrek SB正确指出我在这个答案中使用了术语上的“快速和松散”。我这样做是为了使答案简短易懂。我所说的“在编译时初始化”和“编译时常量”是指标准中第5.19节“常量表达式”[expr.const]所称的整数常量表达式。
整数常量表达式是用所谓的“常量初始化”初始化的,它与零初始化一起被称为“静态初始化”([basic.start.init]/p2)。
我在这里写的任何偏差与标准中的偏差是意外的,标准中的内容是正确的。 </免责声明>

“在编译时初始化”并不是很合理。初始化是程序执行的一部分。“静态初始化”可能更好,尽管我不会反对“在加载时”。此外,C++实际上规定了何时必须静态初始化某些内容(例如const int x = 5;),没有任意性。唯一的任意性是动态初始化可能被提升到静态阶段。 - Kerrek SB
@KerrekSB:好的,没问题。 - Howard Hinnant
所以 const int y = 1984; 和 constexpr int y = 1984; 会生成相同的汇编代码吗?或者不完全相同,但在某种意义上它们不会在运行时进行赋值操作? - NoSenseEtAl
@NoSenseEtAl:完全相同。但是请考虑 const int y = zconstexpr int y = z。在回答问题之前,您必须首先确定 z 是否为整数常量表达式。如果 z 不是整数常量表达式,则后者甚至无法编译。 - Howard Hinnant

5

我是这个视频的作者。

意图.

constexpr清晰地表达了一个编译时不可变值的意图。而const并不真正意味着编译时不可变值

这两个修饰符都可以强制转换,但结果会导致未定义行为。查看DyP的评论以获取更多信息。

在使用C++11时,我认为在处理编译时值时首先要想到的关键字不是const,而应该是constexpr

代码没有constexpr也会完全相同,或者用const代替constexpr也是如此。 但当您查看代码并看到constexpr int windowWidth;时,您可以100%确信这是一个永远不会在运行时更改的不可变常数。


在我的第二个教程视频中(链接),在前三分钟有一个补充说明关于constexpr,展示了constexpr函数和更多的constexpr示例/说明。


3
const”是一个修饰符,甚至可以被强制转换掉,因此它并不真正意味着编译时不可变的值。我认为“constexpr”实际上并不是对象类型的一部分,它只是暗示了“const”,并对类型和初始化添加了限制。无论是已声明为“const”还是“constexpr”的变量都可以被取消常量属性;通过这种非常量路径进行修改会导致未定义行为。重要的是“编译时”,与“constexpr”不同,“const”声明的变量可以用在运行时才能确定的值进行初始化。 - dyp

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