#include <exception> constexpr bool foo(bool x) { return x ? true : throw std::exception(); } int main() { // 1) must never be compiled // static_assert(foo(false),""); // 2) must always be compiled? const bool x = foo(false); // 3) must never compile? constexpr bool y = foo(false); return 0; }
我确定(1)必须导致编译错误.我确信(2)在编译时不能被拒绝,尽管它在运行时会失败.
有趣的情况是constexpr变量(3).在这个简单的例子中,gcc和clang实际上会评估表达式,因此拒绝程序. (错误信息:y不是常量表达式).
每个C11编译器是否强制拒绝该程序?如果foo(false)被更复杂的表达式所替代,该怎么办?
我惊讶地发现,constexpr并不完整,尽管它将在规范的改变之后:
Is constexpr-based computation Turing complete?
也许这与我的问题有关.据我所知,在本例中,编译器被允许推迟对constexpr(3)的实际评估,直到运行时为止.但是,如果constexpr是完整的,我发现很难相信编译器可以决定所有的constexpr是否会抛出异常(这意味着constexpr无效).
解决方法
N3242 7.1.5第9段:
A
constexpr
specifier used in an object declaration declares the object asconst
. Such an object shall have literal type and shall be initialized. If it initialized by a constructor call,that call shall be a constant expression (5.19). Otherwise,every full-expression that appears in its initializer shall be a constant expression. Each implicit conversion used in converting the initializer expressions and each constructor call used for the initialization shall be one of those allowed in a constant expression (5.19).
我认为一个constexpr对象为“在编译时评估”,并且一个constexpr函数或者constexpr构造函数可能在编译时被评估.编译器必须在编译时确定(3)这样的语句的语义有效性.您可以认为“评估”仍然可以在运行时完成,但检查有效性大部分都是正常工作.此外,代码可以继续实例化一个像“检查”一样的模板,这几乎可以保证编译器需要在编译时找出y的值.
这的确意味着你可以编写一个恶作剧程序来使编译器花费很长的时间或无限的时间.但是我怀疑已经有可能与运算符 – >招数.