constexpr的目的是什么?

6
这更像是一个哲学问题,而不是实际的代码片段,但也许C++大师们可以启发我(如果已经问过了,请原谅)。我一直在阅读Meyers的《Effective Modern C++》书中的第15项,以及这个线程:implicit constexpr?(再加上相当数量的谷歌搜索)。该项介绍了使用constexpr来表示表达式,即它定义了函数,可以在编译时输入给定的值并返回编译时值。此外,我提到的StackOverflow线程显示,一些编译器完全能够自行确定哪些函数调用结果在编译时已知。
因此,问题是:与定义编译器何时推导和允许静态/编译时值相比,为什么要将constexpr添加到标准中?我意识到这使得各种仅编译(例如std::array<T,constexpr>)的定义不那么可预测,但另一方面,正如Meyers的书所述,constexpr是接口的一部分,如果您删除它,可能会导致任意数量的客户端代码停止编译。因此,显式constexpr不仅要求人们记住添加它,而且还为接口添加了永久的语义。 澄清:这个问题不是关于为什么应该使用constexpr。我知道在编程时能够推导出编译时值非常有用,并且我自己在许多场合都使用它。这是一个关于为什么在编译器可以自行推导出常量时间行为的情况下,它是强制性的的问题。 澄清2:这是一个代码片段,显示编译器不会自动推导,我在这种情况下使用了g ++。
#include <array>

size_t test()
  {
  return 42;
  }

int main()
  {
  auto i = test();
  std::array<int, i> arrayTst;
  arrayTst[1] = 20;
  return arrayTst[1];
  }

std::array的声明无法编译,因为我没有将test()定义为constexpr,这当然符合标准。如果标准不同,那么gcc就可以独立地发现test()总是返回常量表达式。

这个问题并不是在问“标准定义了什么”,而是在问“为什么标准是这样的”?


可能会有帮助:http://www.stroustrup.com/C++11FAQ.html#constexpr。 - R Sahu
不需要过多思考我的答案,魔数是不好的。如果你的代码可以从易于理解的参数自动计算它们,那么这本身就是一个巨大的优势。例如,我今天刚写了一些使用constexpr在编译时计算crc32的代码,我认为调用一个constexpr函数会更容易阅读,而不是计算出一个谁知道如何计算的魔数。你还可以获得保证,这些东西是在编译时计算的,这在静态全局初始化无法运行的情况下曾经救过我的命。 - tux3
@RomanK 抱歉,我并没有真正回应你的观点。我认为,像其他人指出的那样,你获得行为和接口保证的部分至关重要,否则你可能会在运行时将编译时计算悄悄地转换成运行时计算。这也会引入更多编译器之间的不一致性,但目前这并不是一个大问题。 - tux3
1
@BillyONeal 我认为你不能把简单的常量折叠和constexpr放在同一水平线上。constexpr允许您在编译时运行更复杂的算法,并提供实际保证。 - tux3
@RomanK 要求在常量表达式内可评估的函数声明为constexpr实际上不是原始提案的一部分。它出现在该文件的第二版中;我仍在努力弄清楚其基本原理。 - dyp
显示剩余7条评论
1个回答

6
在使用 constexpr 关键字之前,编译器有时可以找出编译时常量并使用它。然而,程序员无法预知何时会发生这种情况。
使用 constexpr 后,如果一个表达式不是编译时常量,程序员会立即得到通知,并意识到需要修复它。

1
感谢您的快速回答。假设说,为什么constexpr不能是可选的呢?也就是说,如果我想这样做,我可以添加关键字以便在表达式不是常量时得到通知(如您所描述的),但如果我省略它(包括模板参数等),仍然可以获得编译时评估的好处。 - RomanK
@RomanK:你有证据表明你还没有得到那个吗? - Zan Lynx
是的,我在问题中添加了一个示例。如果编译器这样做,那就违反了标准。 - RomanK

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