62

任何只包含 return 语句的函数都可以被声明 ,因此如果所有参数都是并且只有函数在其主体中被调用,constexpr则允许在编译时进行评估。有什么理由不声明任何这样的功能吗?constexprconstexprconstexpr

例子:

  constexpr int sum(int x, int y) { return x + y; }
  constexpr i = 10;
  static_assert(sum(i, 13) == 23, "sum correct");

任何人都可以提供一个声明函数constexpr 会造成任何伤害的例子吗?


一些初步的想法:

即使没有充分的理由声明一个函数constexpr,我也无法想象该constexpr关键字具有过渡作用:它在不需要编译时评估的代码中的缺失将允许不实现编译时评估的编译器仍然可以编译该代码(但在需要它们的代码上可靠地失败,因为使用明确表示constexpr)。

但我不明白的是:如果没有充分的理由声明一个函数 not constexpr,为什么不声明标准库中的每个函数constexpr?(你不能说它还没有完成,因为还没有足够的时间去做,因为为所有人做这件事是不费吹灰之力的——这与决定是否做每一个功能相反constexpr。)—— - 我知道N2976 故意不需要 cstrs 用于许多标准库类型(例如容器),因为这对于可能的实现来说太有限了。让我们将它们排除在参数之外,只是想知道:一旦标准库中的类型实际上有一个constexprcstr,为什么不是每个在它上运行的函数都声明constexpr?

在大多数情况下,您也不能争辩说您可能不喜欢声明函数constexpr,因为您没有设想任何编译时使用:因为如果其他人 evtl. 将使用您的代码,他们可能会看到您没有看到的这种用法。(但当然,对于类型特征类型和类似的东西是允许的。)

所以我想故意不声明一个函数一定有一个很好的理由和一个很好的例子constexpr吗?

(对于“每个函数”,我始终是指:每个满足存在要求的函数constexpr,即,被定义为单个 return 语句,只接受具有 constexpr cstrs 类型的参数并且只调用constexpr函数。从 C++14 开始,更多在此类函数的主体中是允许的:例如,C++14 constexpr 函数可以使用局部变量和循环,因此可以声明更广泛的函数类constexpr。)

问题为什么要std::forward丢弃constexpr-ness?是这个的一个特例。

4

3 回答 3

37

constexpr只有遵循以下规则才能声明函数constexpr——没有动态转换、没有内存分配、没有对非constexpr函数的调用等。

在标准库中声明一个函数constexpr要求所有实现都遵守这些规则。

首先,这需要检查每个可以实现为的功能constexpr,这是一项漫长的工作。

其次,这对实现是一个很大的限制,并且会禁止许多调试实现。因此,只有当收益超过成本,或者要求足够严格以至于实施几乎必须遵守constexpr规则时,它才是值得的。对每个功能进行这种评估又是一项漫长的工作。

于 2011-02-25T10:59:16.653 回答
15

我认为您所指的是所谓的部分评估。您要说的是,某些程序可以分为两部分-需要运行时信息的部分,以及无需任何运行时信息即可完成的部分-理论上您可以完全评估程序的一部分在您开始运行程序之前,它不需要任何运行时信息。有一些编程语言可以做到这一点。例如,D 编程语言在编译器中内置了一个解释器,它允许您在编译时执行代码,前提是它满足某些限制。

使部分评估工作存在一些主要挑战。首先,它极大地使编译器的逻辑复杂化,因为编译器需要能够模拟所有可以在编译时放入可执行程序的操作。在最坏的情况下,这需要您在编译器内部拥有一个完整的解释器,从而产生一个难题(编写一个好的 C++ 编译器)并使其更难实现。

我相信当前规范的原因constexpr仅仅是为了限制编译器的复杂性。它仅限于检查的情况相当简单。无需在编译器中实现循环(这可能会导致其他一系列问题,例如如果您在编译器中获得无限循环会发生什么)。它还避免了编译器可能不得不评估可能在运行时导致段错误的语句,例如跟随错误的指针。

要记住的另一个考虑因素是某些功能具有副作用,例如读取cin或打开网络连接。像这样的函数根本无法在编译时进行优化,因为这样做需要仅在运行时可用的知识。

总而言之,没有理论上的理由不能在编译时部分评估 C++ 程序。事实上,人们一直都在这样做。例如,优化编译器本质上是尽可能多地尝试这样做的程序。模板元编程是 C++ 程序员尝试在编译器内执行代码的一个实例,部分原因是模板的规则形成了一种函数式语言,编译器更容易实现它,因此模板可以做一些很棒的事情。此外,如果您考虑编译器作者时间和编程时间之间的权衡,模板元编程表明,如果您可以让程序员向后弯腰以获得他们想要的东西,您可以构建一个非常弱的语言(模板系统)并保持语言复杂简单。

希望这可以帮助!

于 2011-02-25T04:29:42.130 回答
4

如果函数有副作用,你就不想标记它constexpr例子

我不能从中得到任何意想不到的结果,实际上它看起来像gcc 4.5.1 只是忽略constexpr

于 2011-02-25T05:15:41.877 回答