constexpr
允许在编译时评估的表达式在编译时进行评估。
为什么这个关键字甚至是必要的?为什么不允许或要求编译器在编译时评估所有表达式?如果可能的话?
标准库的constexpr应用不均匀,这会带来很多不便。使constexpr成为“默认”将解决这个问题,并可能改进大量现有代码。
答案 0 :(得分:16)
已经允许在as-if规则下在编译时评估无副作用的计算。
constexpr
所做的是保证合规编译器需要执行哪些数据流分析,以检测 1 编译时可计算表达式,并且还允许程序员表达该意图,以便他们在意外地执行无法预先计算的事情时获得诊断。
使constexpr
成为默认值会消除这种非常有用的诊断能力。
1 一般来说,如果可能的话,要求"在编译时评估所有表达式"是一个非首发,因为检测"如果可能"需要解决停机问题,计算机科学家知道在一般情况下这是不可能的。因此,在输出为{"可在编译时计算","在编译时无法计算或无法决定&# 34; }。并且不同编译器决定的能力将取决于他们的测试有多聪明,这将使该功能不可移植。 constexpr
定义要使用的确切测试。更智能的编译器仍然可以预先计算比标准测试指令更多的表达式,但如果它们未通过测试,则不能将它们标记为constexpr
。
答案 1 :(得分:4)
注意:尽管如下,我承认喜欢将constexpr作为默认值。但是你问为什么还没有完成,所以回答一下我将简单地阐述mattnewport的最后评论:
考虑今天的情况。您正在尝试在需要常量表达式的上下文中使用标准库中的某些函数。它没有标记为constexpr,因此您收到编译器错误。这看起来很愚蠢,因为“明确地”需要改变的唯一的事情就是在定义中添加constexpr这个词。
现在考虑我们采用您的提案的替代宇宙中的生活。你的代码现在编译,是的!明年,您决定将Windows支持添加到您正在处理的任何项目中。它能有多难?您将使用Visual Studio为您的Windows用户编译并继续为其他人使用gcc,对吧?
但是第一次尝试在Windows上编译时,会出现一堆编译器错误:此函数不能用于常量表达式上下文中。您查看相关函数的代码,并将其与gcc附带的版本进行比较。事实证明它们略有不同,并且gcc随附的版本完全符合constexpr的技术要求,同样,Visual Studio附带的版本也不能满足这些要求,再次是纯粹的意外。现在怎么样?
你说没问题,我会向微软提交一份错误报告:这个功能应该修复。他们关闭你的错误报告:标准永远不会说这个函数必须在常量表达式中可用,所以我们可以实现我们想要的。所以你向gcc维护者提交了一个错误报告:你为什么不警告我我使用的是不可移植的代码?他们也把它关闭了:我们怎么知道它不便携?我们无法跟踪其他人如何实现标准库。
现在怎样?没有人做错任何事。不是你,不是gcc人,也不是Visual Studio人。然而,你仍然最终得到了不可移植的代码,而且此时并不是一个快乐的露营者。在其他条件相同的情况下,一个好的语言标准会尽量使这种情况变得不可能。
即使我使用了不同编译器的示例,当您尝试升级到同一编译器的较新版本,甚至尝试使用不同的设置进行编译时,也会发生这种情况。例如:该函数包含一个断言语句,以确保使用有效参数调用它。如果在禁用断言的情况下编译,则断言“消失”并且函数符合constexpr的规则;如果你启用断言,那么它不符合它们。 (现在这种情况不太可能,因为constexpr的规则非常慷慨,但在C ++ 11规则下这是一个更大的问题。但原则上,这一点在今天仍然存在。)
最后,我们得到了一个小错误的错误消息。在今天的世界中,如果我尝试在constexpr函数中执行类似于cout
语句的操作,我会立即得到一个简单的错误。在您的世界中,我们将拥有与模板相同的情况,深层堆栈跟踪一直到输出流实现的最底层。不是致命的,但肯定很烦人。
这已经晚了一年半,但我仍然希望它有所帮助。
答案 2 :(得分:1)
正如Ben Voigt所指出的,编译器已经被允许在as-if规则下在编译时评估任何内容。
constexpr
的作用还包括明确的表达式,可以在编译时常量所需的地方使用。这意味着我可以编写这样的代码并知道它是可移植的:
constexpr int square(int x) { return x * x; }
...
int a[square(4)] = {};
...
如果没有标准中的关键字和明确规则,我不确定如何以可移植的方式指定它,并对程序员想要constexpr
但不符合要求的事情提供有用的诊断。