What happens when an exception is thrown while computing a constexpr?

妖精的绣舞 提交于 2019-12-21 03:33:26

问题


When computing constant expressions to initialize a constexpr it is possible to throw exceptions. For example here is an example where the computation of a constant expression is guarded against overflow:

#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";
    }
}

The first call to f() just shows that a constexpr can be computed. The second call to f() isn't used to initialize a constexpr and throws a run-time exception. The third call to f() is used to initialize a constexpr but that point won't ever reached because an exception is thrown. However, what should happen in this case? I would expect the handler in the catch-clause is executed but both gcc and clang produce a compile-time error.


回答1:


The initialiser for a constexpr variable must be a constant expression (C++11 §7.1.5/9):

A constexpr specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized. If it is initialized by a constructor call, [...]. Otherwise, or if a constexpr specifier is used in a reference declaration, every full-expression that appears in its initializer shall be a constant expression.

Note the following requirements for a constant expression (§5.19/2):

A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression, but subexpressions of [...] conditional operations that are not evaluated are not considered

  • [...]

  • an invocation of a constexpr function with arguments that, when substituted by function invocation substitution (7.1.5), do not produce a constant expression;

  • [...]

  • a throw-expression (15.1).

Function invocation substitution for a constexpr function is defined as follows (§7.1.5/5):

Function invocation substitution for a call of a constexpr function [...] means implicitly converting each argument to the corresponding parameter type as if by copy-initialization, substituting that converted expression for each use of the corresponding parameter in the function-body, and [...] implicitly converting the resulting returned expression or braced-init-list to the return type of the function as if by copy-initialization. Such substitution does not change the meaning.

As we saw above (§5.19/2), subexpressions of conditional operations that are not evaluated are not considered. f(42) is not a constant expression because when you perform function invocation substitution on f, it results in an expression with a throw expression on the side of the conditional operation that is evaluated. On the other hand, for f(41), the throw ends up on the side that isn't evaluated.

So the program is ill-formed. It doesn't matter whether the initialiser is actually reached or not because the program shouldn't compile.



来源:https://stackoverflow.com/questions/20870233/what-happens-when-an-exception-is-thrown-while-computing-a-constexpr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!