为什么C ++ 11 constexpr如此限制?

如您所知,C ++ 11引入了constexpr关键字。

C ++ 11引入了关键字constexpr,它允许用户保证函数或对象构造函数是编译时常量。 […]这允许编译器了解并validation[函数名称]是编译时常量。

我的问题是为什么有这样严格的限制,可以宣布的function的forms。 我明白希望保证这个function是纯粹的,但考虑一下:

在函数上使用constexpr会对函数的function施加一些限制。 首先,函数必须有一个非空的返回types。 其次,函数体不能声明variables或定义新的types。 第三,主体可能只包含声明,空语句和单个返回语句。 必须存在参数值,以便在参数replace之后,return语句中的expression式会生成一个常量expression式。

这意味着这个纯粹的function是非法的:

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

你也不能定义局部variables… :(所以我想知道这是一个devise决定,还是做编译器吮吸,当涉及到certificate函数是纯粹的?

您需要编写语句而不是expression式的原因是您要利用语句的附加function,特别是循环的能力。 但要有用,这将需要能够声明variables(也被禁止)。

如果您将用于循环的工具(包含可变variables)与逻辑分支(如if语句)结合使用,则可以创build无限循环。 不可能确定这样一个循环是否会终止( 暂停问题 )。 因此有些源会导致编译器挂起。

通过使用recursion纯函数,可以引起无限recursion,这可以被certificate对上述循环能力等效。 然而,C ++在编译时就已经存在这个问题 – 它是在模板扩展的情况下发生的 – 所以编译器必须有一个“模板堆栈深度”的开关,以便知道何时放弃。

所以这些限制似乎是为了确保这个问题(确定一个C ++编译是否完成)不会比现在更棘手。

constexpr函数的规则被devise成不可能写出一个有任何副作用的constexpr函数。

通过要求constexpr没有副作用,用户不可能确定实际评估的地点/时间。 这一点很重要,因为constexpr函数在编译时和运行时都可以在编译器的判断下发生。

如果允许有副作用,则需要遵守一些关于观察次序的规则。 这将是难以置信的定义 – 甚至比static初始化顺序更难。

保证这些函数免于副作用的一套相对简单的规则是要求它们只是一个单一的expression式(除此之外还有一些额外的限制)。 这听起来很有限,并且如你所logging的那样排除了if语句。 虽然这种特殊的情况下没有任何副作用,但是会给规则带来额外的复杂性,并且考虑到你可以使用三元运算符或recursion地编写相同的东西,这并不是什么大问题。

n2235是在C ++中提出了constexpr的文章。 它讨论了devise的合理性 – 有关引用似乎是从析构函数的讨论中得到的,但是通常是相关的:

原因在于,常量expression式意在由编译器在翻译时进行评估,就像任何其他内置types的文字一样; 特别是不允许有明显的副作用。

有趣的是,本文还提到以前的一个build议是,编译器自动计算出哪些函数没有新的关键字就是constexpr ,但是这被发现是复杂的,这似乎支持我的build议,即规则devise得很简单。

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

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

这些限制当然可以提升很多,而不需要在编译期间启用不能执行的代码,或者不能被certificate始终停止的代码。 不过,我猜这是因为没有完成

  • 这会使编译器以最小的收益复杂化。 C ++编译器是相当复杂的

  • 在不违反上述限制的情况下准确地指定允许的数量将是非常耗时的,并且为了使标准离开,推迟了期望的特征,可能没有增加更多工作的动力(并且进一步推迟标准),收益不大

  • 一些限制可能是相当任意的或相当复杂的(特别是在循环中,因为C ++没有循环本地递增的概念,但是terminal条件和增量代码都必须在for语句,可以为它们使用任意expression式)

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

我认为constexpr只是为了const对象。 我的意思是; 你现在可以有静态常量对象像String::empty_string静态构造(没有黑客!)。 这可能会缩短'main'调用之前的时间。 而静态常量对象可能有像.length(), operator==,...这样的函数.length(), operator==,...所以这就是为什么'expr'是需要的。 在'C'中,你可以创build如下的静态常量结构:

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

Linux内核拥有大量的这种types的类。 在c ++中,你可以用constexpr来做到这一点。

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

 constexpr int maybeInCppC1Y(int a, int b) { return (a > 0) ? (a + b) : (a - b); }