Die*_*ühl 14 c++ exception language-lawyer constexpr c++11
计算常量表达式以初始化时constexpr,可以抛出异常.例如,这里是一个示例,其中一个常量表达式的计算被防止溢出:
#include <iostream>
#include <stdexcept>
constexpr int g(int n, int n0, int n1) {
return n == 0? n1: g(n - 1, n1, n0 + n1);
}
constexpr int f(int n) {
return n < 42? g(n, 0, 1): throw std::out_of_range("too big");
}
int main()
{
try {
constexpr int f41 = f(41); // OK: constexpr
int f43 = f(43); // OK: throws an exception
constexpr int f42 = f(42); // not OK but what happens?
}
catch (std::exception const& ex) {
std::cout << "ERROR: " << ex.what() << "\n";
}
}
Run Code Online (Sandbox Code Playgroud)
第一次调用f()只显示a constexpr可以计算.第二次调用f()不用于初始化a constexpr并抛出运行时异常.第三个调用f()用于初始化a,constexpr但由于抛出异常,因此无法达到该点.但是,在这种情况下会发生什么?我希望catch-clause中的处理程序被执行但gcc和clang都会产生编译时错误.
Jos*_*eld 12
constexpr变量的初始化必须是常量表达式(C++11§7.1.5/ 9):
constexpr对象声明中使用的说明符将对象声明为const.这样的对象应具有文字类型并应初始化.如果它是由构造函数调用初始化的,[...].否则,或者如果constexpr在引用声明中使用了说明符,则其初始值设定项中出现的每个完整表达式都应是常量表达式.
请注意常量表达式的以下要求(§5.19/ 2):
甲条件表达式是一个核心常量表达式除非它涉及以下作为一个潜在的评价子表达式中的一个,但子表达式[...]未评价不被认为是条件操作
[...]
调用
constexpr带有参数的函数,当被函数调用替换(7.1.5)替换时,不生成常量表达式;[...]
一个throw-expression(15.1).
函数的函数调用替换constexpr定义如下(第7.1.5/5节):
功能调用替换为一个的呼叫
constexpr函数[...]意味着由复制初始化,代该转换表达式,为在每次使用中的相应参数的隐含每个参数转化为相应的参数类型仿佛功能体,和[ ...]将生成的返回表达式或braced-init-list隐式转换为函数的返回类型,就像通过复制初始化一样.这种替代不会改变其含义.
如上所述(§5.19/ 2),未考虑未评估的条件操作的子表达式.f(42)不是常量表达式,因为当您执行函数调用替换时f,它会生成一个表达式,该throw表达式在计算的条件运算一侧.另一方面,因为f(41),throw最终在未评估的一侧.
所以该计划是不正确的.是否实际达到初始化并不重要,因为程序不应该编译.
| 归档时间: |
|
| 查看次数: |
1487 次 |
| 最近记录: |