不可能不是这种情况,因为并非constexpr函数的每个inovocation都必须能够被评估为核心常量表达式的子表达式.我们只需要一个允许这个的参数值.因此,只要我们有一个不调用该分支的参数值,constexpr函数就可以包含一个throw语句.
这在C++ 14标准草案章节7.1.5
constexpr说明符[dcl.constexpr]中有所介绍,它告诉我们constexpr函数允许的内容:
constexpr函数的定义应满足以下约束:
它不应是虚拟的(10.3);
其返回类型应为字面类型;
每个参数类型都应是文字类型;
它的函数体应为= delete,= default或不包含的复合语句
asm-definition,
一个goto声明,
尝试块,或
非文字类型或静态或线程存储持续时间的变量的定义,或者不执行初始化的定义.
我们可以看到它并不禁止throw
,事实上禁止很少,因为对constexpr函数提议的放宽限制成为C++ 14的一部分.
下面我们看到规则说如果至少存在一个参数值,则constexpr函数是格式良好的,这样它就可以被计算为核心常量表达式的子表达式:
对于非模板,非默认的constexpr函数或非模板,非默认的,非继承的constexpr构造函数,如果不存在参数值,则调用函数或构造函数可以是核心常量的计算子表达式表达式(5.19),程序不正确 ; 无需诊断.
在本段下面我们有以下示例,其中显示了此案例的完美示例:
constexpr int f(bool b) { return b ? throw 0 : 0; } // OK constexpr int f() { return f(true); } // ill-formed, no diagnostic required
所以我们期望以下示例的输出:
#includeconstexpr int f(bool b) { return b ? throw 0 : 0; } int main() { std::cout << noexcept( f(1) ) << "\n" << noexcept( f(0) ) << "\n" ; }
是(看到它与gcc一起生活):
0 1
通过webcompiler的 Visual Studio 也会产生相同的结果.正如hvd所指出的那样,clang有一个错误,如bug报告所述,noexcept应检查表达式是否为常量表达式.
缺陷报告1129
缺陷报告1129:constexpr函数的默认值nothrow询问相同的问题:
不允许constexpr函数通过异常返回.这应该被识别,并且声明constexpr而没有显式异常规范的函数应该被视为声明为noexcept(true)而不是通常的noexcept(false).对于声明constexpr而没有显式异常规范的函数模板,当且仅当在给定实例化上遵守constexpr关键字时,才应将其视为noexcept(true).
而回应是:
前提是不正确的:只有在需要常量表达式的上下文中调用constexpr函数时才禁止异常.用作普通函数,它可以抛出.
并修改了5.3.7 [expr.unary.noexcept]第3段子弹1(另外强调指出):
一个可能被评估的函数,成员函数,函数指针或成员函数指针的call80,它没有非抛出异常规范(15.4 [except.spec]),除非调用是一个常量表达式(5.20 [expr.常量]),
有人说的noexcept
是:
如果表达式包含对任何类型的没有非抛出异常规范的函数的调用,则结果为false,除非它是常量表达式.
而且,关于constexpr
,确实如此:
对于常量表达式,noexcept运算符始终返回true
在任何情况下,它似乎都没有暗示说明constexpr
符强制包含noexcept
表达式的说明符,正如有人在评论中显示的反例并且您也验证了.
总之,从文档,有大约之间的关系如下有趣的说明noexcept
和constexpr
:
因为noexcept运算符总是为常量表达式返回true,所以它可以用于检查constexpr函数的特定调用是否采用常量表达式分支
编辑:GCC的例子
感谢@hvd对GCC关于我的最后一句话的有趣评论/例子.
constexpr int f(int i) { return i == 0 ? i : f(i - 1); } int main() { noexcept(f(512)); return noexcept(f(0)) == noexcept(f(0)); }
上面的代码返回0
,并警告该语句noexcept(f(512))
无效.
在评论那个据说没有效果的陈述时,返回值会变为1
.
编辑:已知的铿锵声
再次感谢@hvd也提供了这个链接,这是关于clang中关于代码中提到的代码的一个众所周知的错误.
从错误报告中引用:
在C++的书中,[expr.unary.noexcept] p3:
"如果在潜在评估的上下文中,表达式将包含对函数,成员函数,函数指针或不具有非抛出异常规范的成员函数指针的潜在评估调用,则noexcept运算符的结果为false (15.4),除非调用是常数表达式(5.19) ".
我们没有实现最后一个短语.