为什么C ++ 11 constexpr如此严格?

您可能知道,C ++ 11引入了constexpr关键字。

C ++ 11引入了关键字constexpr,它使用户可以   确保函数或对象构造函数是编译时   不变。   [...]   这使编译器可以理解并验证[函数名]是否为   编译时常数。

我的问题是为什么对可以声明的函数形式有如此严格的限制。 我了解保证功能纯净的愿望,但请考虑以下因素:

在函数上使用constexpr对什么施加了一些限制   该功能可以做到。 首先,该函数必须具有非空返回   类型。 其次,函数体不能声明变量或定义新的   类型。 第三,主体只能包含声明,空语句   和一个return语句。 必须存在这样的参数值   在替换参数之后,返回中的表达式   语句产生一个常量表达式。

这意味着此纯函数是非法的:

constexpr int maybeInCppC1Y(int a, int b)
{
    if (a>0)
        return a+b;
    else
        return a-b;
  //can be written as   return  (a>0) ? (a+b):(a-b); but that isnt the point
}

你也不能定义局部变量... :(所以我想知道这是一个设计决定,还是编译器在证明函数a是纯函数时会很烂?

NoSenseEtAl asked 2020-01-13T19:26:09Z
5个解决方案
28 votes

您需要编写语句而不是表达式的原因是,您想利用语句的其他功能,尤其是循环功能。 但是要有用,那将需要声明变量的能力(也被禁止)。

如果将用于可变变量的循环工具与逻辑分支结合在一起(如if语句中所示),则可以创建无限循环。 无法确定这样的循环是否会终止(停止问题)。 因此,某些源将导致编译器挂起。

通过使用递归纯函数,可以导致无限递归,这可以证明对上述循环功能具有同等的功能。 但是,C ++在编译时就已经存在该问题-它是在模板扩展时发生的-因此,编译器已经必须具有“模板堆栈深度”的开关,以便他们知道何时放弃。

因此,这些限制似乎旨在确保此问题(确定C ++编译是否会完成)不会比现在更棘手。

Daniel Earwicker answered 2020-01-13T19:26:42Z
28 votes

constexpr函数的规则经过设计,因此不可能编写有任何副作用的constexpr函数。

通过要求constexpr没有副作用,用户无法确定在何处/何时对其进行实际评估。 这很重要,因为编译器可以自行决定在编译时和运行时都允许constexpr函数发生。

如果允许副作用,那么将需要一些关于观察顺序的规则。 这将很难定义,甚至比constexpr初始化顺序问题更难定义。

保证这些功能没有副作用的一套相对简单的规则是要求它们只是一个表达式(除此之外,还有一些其他限制)。 最初,这听起来很局限,并且如您所述排除了if语句。 尽管该特定情况没有副作用,但它会给规则带来额外的复杂性,并且鉴于您可以使用三元运算符来编写相同的东西,或者递归地编写,这并不是一件大事。

n2235是在C ++中提出constexpr加法的论文。 它讨论了设计的合理性-相关的引言似乎是关于析构函数的讨论中的引文,但一般而言是相关的:

原因是常量表达式打算由编译器评估   在翻译时,就像其他任何内置类型的文字一样; 特别是没有   允许观察到副作用。

有趣的是,该论文还提到了一个先前的建议,建议编译器自动找出哪些函数是constexpr,而没有new关键字,但是发现这太复杂了,这似乎支持了我的建议,即规则设计得很简单。

(我怀疑本文引用的参考文献中还会有其他引号,但这涵盖了我关于无副作用的论点)

Flexo answered 2020-01-13T19:27:36Z
12 votes

实际上,C ++标准化委员会正在考虑删除c ++ 14的一些约束。 参见以下工作文件[http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3597.html]

hivert answered 2020-01-13T19:27:56Z
3 votes

如果不启用在编译期间无法执行的代码,或者无法证明始终停止的代码,则可以一定程度地解除限制。 但是我想这没有完成,因为

  • 它会使编译器复杂化,从而获得最小的收益。 C ++编译器非常复杂

  • 在不违反上述限制的情况下准确指定允许的数量将非常耗时,并且由于推迟了所需功能以使标准失效,因此几乎没有动力增加更多工作(并且进一步拖延了工作时间)。 标准)几乎没有收益

  • 其中一些限制要么相当随意,要么相当复杂(特别是在循环中,因为C ++没有本机递增循环的概念,但最终条件和递增代码都必须在 for语句,可以为它们使用任意表达式)

当然,只有标准委员会的一名成员才能给出我的假设是否正确的权威答案。

celtschk answered 2020-01-13T19:28:35Z
-4 votes

我认为constexpr仅用于const对象。 我的意思是; 您现在可以拥有静态const对象,例如String::empty_string可以静态构造(无需黑客入侵!)。 这可以减少调用“ main”之前的时间。 而且静态const对象可能具有类似于.length(), operator==,...的功能,因此这就是为什么需要“ expr”的原因。 在“ C”中,您可以创建静态常量结构,如下所示:

static const Foos foo = { .a = 1, .b = 2, };

Linux内核具有大量此类类型的类。 在c ++中,您现在可以使用constexpr进行此操作。

注意:我不知道,但是下面的代码不应被接受,例如版本:

constexpr int maybeInCppC1Y(int a, int b) { return (a > 0) ? (a + b) : (a - b); }
Abdurrahim answered 2020-01-13T19:29:05Z
translate from https://stackoverflow.com:/questions/8308812/why-is-c11-constexpr-so-restrictive