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

NoS*_*tAl 52 c++ constexpr c++11

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

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

我的问题是为什么对可以声明的函数的形式有严格的限制.我理解保证功能是纯粹的愿望,但考虑到这一点:

在函数上使用constexpr会对函数的作用施加一些限制.首先,该函数必须具有非void返回类型.其次,函数体不能声明变量或定义新类型.第三,正文可能只包含声明,空语句和单个return语句.必须存在参数值,以便在参数替换后,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
}
Run Code Online (Sandbox Code Playgroud)

你也不能定义局部变量... :(所以我想知道这是一个设计决定,还是编译器吮吸来证明功能a是纯粹的?

Dan*_*ker 28

您需要编写语句而不是表达式的原因是您希望利用语句的附加功能,尤其是循环功能.但要有用,那就需要能够声明变量(也被禁止).

如果将用于循环的工具与可变变量和逻辑分支(如if语句中)结合起来,那么您就能够创建无限循环.无法确定这样的循环是否会终止(停止问题).因此,某些源会导致编译器挂起.

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

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

  • `你需要编写语句的原因[是] ...循环的能力.我不同意,我想要`if` /`else`和本地`const`对象以获得代码可读性,两者都不应该(应该)为编译器添加_any_问题. (15认同)
  • 对我来说,"副作用"的解释似乎更有可能,但有没有人真正知道背后的理由,而不是猜测它? (4认同)
  • 根据定义,导致编译器挂起的源应视为无效.编译器可能会也可能不会选择尝试检测它.这并不意味着编译整个类源代码是不可能的.这与暂停问题无关.C++ 14确实允许constexpr函数中的循环. (3认同)
  • "因此,某些来源会导致编译器挂起." 这是一个弥补问题.真实世界模板扩展导致编译器常规挂起,因为现代C++编译器必须实现编译时**函数**语言解释器,这比**命令式**语言解释器要困难得多.在现实生活中,这绝不是一个问题:编译时程序挂起 - >你有一个bug.有什么大不了的. (3认同)
  • @DanielEarwicker当您的程序执行该运行时,您可以检测它.编译时间没有任何不同.例如,LISP宏允许您在编译时运行任意代码,LISP具有此功能 - 现在是20年?您可以使用LISP支持的命令式,功能性,声明式或任何其他样式进行编码.这一切都得到了很好的利用.实际上,C++在该领域存在缺陷. (2认同)

Fle*_*exo 28

constexpr函数规则的设计使得编写具有任何副作用的函数是不可能的constexpr.

通过要求constexpr没有副作用,用户不可能确定实际评估的位置/时间.这很重要,因为constexpr允许函数在编译时和编译时自行决定.

如果允许副作用,那么就需要对它们被观察的顺序有一些规则.这将非常难以定义 - 甚至比static初始化订单问题更难.

用于保证这些函数无副作用的一组相对简单的规则是要求它们只是一个表达式(除此之外还有一些额外的限制).这听起来很有限,并排除了你所说的if语句.虽然这个特殊情况没有副作用,但它会在规则中引入额外的复杂性,并且假设你可以使用三元运算符编写相同的东西,或者递归地说它并不是真正的大问题.

n2235constexpr在C++ 中提出添加的论文.它讨论了设计的合理性 - 相关引用似乎是关于析构函数的讨论,但通常相关:

原因是编译器在翻译时要编译一个常量表达式,就像任何其他内置类型的文本一样; 特别是不允许有可观察到的副作用.

有趣的是,该论文还提到,之前的提案建议编译器自动计算出哪些函数constexpr没有新的关键字,但发现这是非常复杂的,这似乎支持了我的建议,即规则设计简单.

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

  • 你的开头句不正确.constexpr函数允许有副作用.但是,必须存在他们没有的论据.这是合法的:int arbitaryEffect(); constexpr int f(bool b){return b?0:arbitraryEffect(); } (6认同)
  • 鉴于它们必须在使用前必须在TU中定义,看起来似乎并不难以确定`constexpr`功能.如果引用的所有变量都是`const`,并且所有被调用的函数都已经是`constexpr`,那么它就是`constexpr`.否则,它不是'constexpr`.我认为停止问题是更大的担忧. (2认同)

hiv*_*ert 12

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