为什么**不**将函数声明为“constexpr”?

发布于 2024-10-19 12:55:58 字数 1763 浏览 11 评论 0原文

任何仅包含 return 语句的函数都可以被声明 constexpr 因此将允许在编译时进行评估(如果全部) 参数是 constexpr,并且在其主体中仅调用 constexpr 函数。 有什么理由不声明任何这样的函数constexpr

示例:

  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,为什么不是every函数 在标准库中声明constexpr? (你不能争论 尚未完成,因为还没有足够的时间 这样做,因为为所有做这件事是理所当然的——这与为每个函数决定是否使其constexpr相反。) --- 我知道 N2976 许多标准库类型故意不需要 cstr,例如 作为容器,因为这对于可能的情况来说太有限了 实施。让我们将它们排除在争论之外,只是想知道: 一旦标准库中的类型实际上具有 constexpr cstr,为什么不是每个对其进行操作的函数都声明为 constexpr

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

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

(“每个功能”我总是指:每个满足 成为 constexpr 的要求,即被定义为单个 return 语句,仅接受 constexpr 类型的参数 cstrs 并仅调用 constexpr 函数。自 C++14 起,此类函数体内允许执行更多操作:例如,C++14 constexpr 函数可以使用局部变量和循环,因此可以声明更广泛的函数类 constexpr。)

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

Any function that consists of a return statement only could be declared
constexpr and thus will allow to be evaluated at compile time if all
arguments are constexpr and only constexpr functions are called in its body. Is there any reason not to declare any such function constexpr ?

Example:

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

Could anyone provide an example where declaring a function constexpr
would do any harm?


Some initial thoughts:

Even if there should be no good reason for ever declaring a function
not constexpr I could imagine that the constexpr keyword has a
transitional role: its absence in code that does not need compile-time
evaluations would allow compilers that do not implement compile-time
evaluations still to compile that code (but to fail reliably on code
that needs them as made explict by using constexpr).

But what I do not understand: if there should be no good reason for
ever declaring a function not constexpr, why is not every function
in the standard library declared constexpr? (You cannot argue
that it is not done yet because there was not sufficient time yet to
do it, because doing it for all is a no-brainer -- contrary to deciding for every single function if to make it constexpr or not.)
--- I am aware that N2976
deliberately not requires cstrs for many standard library types such
as the containers as this would be too limitating for possible
implementations. Lets exclude them from the argument and just wonder:
once a type in the standard library actually has a constexpr cstr, why is not every function operating on it declared constexpr?

In most cases you also cannot argue that you may prefer not to declare a function constexpr simply because you do not envisage any compile-time usage: because if others evtl. will use your code, they may see such a use that you do not. (But granted for type trait types and stuff alike, of course.)

So I guess there must be a good reason and a good example for deliberately not declaring a function constexpr?

(with "every function" I always mean: every function that meets the
requirements for being constexpr, i.e., is defined as a single
return statement, takes only arguments of types with constexpr
cstrs and calls only constexpr functions. Since C++14, much more is allowed in the body of such function: e.g., C++14 constexpr functions may use local variables and loops, so an even wider class of functions could be declared constexpr.)

The question Why does std::forward discard constexpr-ness? is a special case of this one.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

请叫√我孤独 2024-10-26 12:55:58

仅当函数遵守 constexpr 规则时,才能声明 constexpr --- 没有动态转换、没有内存分配、没有对非 constexpr 的调用> 函数等。

将标准库中的函数声明为 constexpr 要求所有实现都遵守这些规则。

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

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

Functions can only be declared constexpr if they obey the rules for constexpr --- no dynamic casts, no memory allocation, no calls to non-constexpr functions, etc.

Declaring a function in the standard library as constexpr requires that ALL implementations obey those rules.

Firstly, this requires checking for each function that it can be implemented as constexpr, which is a long job.

Secondly, this is a big constraint on the implementations, and will outlaw many debugging implementations. It is therefore only worth it if the benefits outweigh the costs, or the requirements are sufficiently tight that the implementation pretty much has to obey the constexpr rules anyway. Making this evaluation for each function is again a long job.

你不是我要的菜∠ 2024-10-26 12:55:58

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

进行部分评估存在一些主要挑战。首先,它使编译器的逻辑变得非常复杂,因为编译器需要能够模拟在编译时可以放入可执行程序中的所有操作。在最坏的情况下,这需要您在编译器内部有一个完整的解释器,这会导致一个困难的问题(编写一个好的 C++ 编译器)并使其更难完成。

我认为当前关于 constexpr 的规范的原因只是为了限制编译器的复杂性。它所限制的情况很容易检查。不需要在编译器中实现循环(这可能会导致一系列其他问题,例如如果编译器内部出现无限循环会发生什么)。它还避免了编译器可能必须评估可能在运行时导致段错误的语句,例如遵循错误的指针。

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

总而言之,理论上没有理由不能在编译时部分评估 C++ 程序。事实上,人们一直在这样做。例如,优化编译器本质上是尝试尽可能做到这一点的程序。模板元编程是 C++ 程序员尝试在编译器内执行代码的一个实例,并且可以使用模板做一些伟大的事情,部分原因是模板的规则形成了一种函数式语言,编译器更容易实现。此外,如果你考虑编译器作者时间和编程时间之间的权衡,模板元编程表明,如果你可以让程序员竭尽全力来获得他们想要的东西,你可以构建一种相当弱的语言(模板系统)并保持语言复杂简单。 (我说“弱”是指“不是特别具有表达能力”,而不是可计算性理论意义上的“弱”)。

希望这有帮助!

I think what you're referring to is called partial evaluation. What you're touching on is that some programs can be split into two parts - a piece that requires runtime information, and a piece that can be done without any runtime information - and that in theory you could just fully evaluate the part of the program that doesn't need any runtime information before you even start running the program. There are some programming languages that do this. For example, the D programming language has an interpreter built into the compiler that lets you execute code at compile-time, provided that it meets certain restrictions.

There are a few main challenges in getting partial evaluation working. First, it dramatically complicates the logic of the compiler because the compiler will need to have the ability to simulate all of the operations that you could put into an executable program at compile-time. This, in the worst case, requires you to have a full interpreter inside of the compiler, making a difficult problem (writing a good C++ compiler) and making it orders of magnitude harder to do.

I believe that the reason for the current specification about constexpr is simply to limit the complexity of compilers. The cases it's limited to are fairly simple to check. There's no need to implement loops in the compiler (which could cause a whole other slew of problems, like what happens if you get an infinite loop inside the compiler). It also avoids the compiler potentially having to evaluate statements that could cause segfaults at runtime, such as following a bad pointer.

Another consideration to keep in mind is that some functions have side-effects, such as reading from cin or opening a network connection. Functions like these fundamentally can't be optimized at compile-time, since doing so would require knowledge only available at runtime.

To summarize, there's no theoretical reason you couldn't partially evaluate C++ programs at compile-time. In fact, people do this all the time. Optimizing compilers, for example, are essentially programs that try to do this as much as possible. Template metaprogramming is one instance where C++ programmers try to execute code inside the compiler, and it's possible to do some great things with templates partially because the rules for templates form a functional language, which the compiler has an easier time implementing. Moreover, if you think of the tradeoff between compiler author hours and programming hours, template metaprogramming shows that if you're okay making programmers bend over backwards to get what they want, you can build a pretty weak language (the template system) and keep the language complexity simple. (I say "weak" as in "not particularly expressive," not "weak" in the computability theory sense).

Hope this helps!

遗心遗梦遗幸福 2024-10-26 12:55:58

如果函数有副作用,您不希望将其标记为 constexpr示例

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

If the function has side effects, you would not want to mark it constexpr. Example

I can't get any unexpected results from that, actually it looks like gcc 4.5.1 just ignores constexpr

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文