Ori*_*ent 33 c++ inline noexcept constexpr c++14
constexpr说明noexcept符是否意味着函数的说明符?对类似问题的回答对说明者说"是" inline,但Eric Niebler的文章让我想知道对当前问题的可能答案.在我看来,答案取决于使用constexpr函数的上下文:是常量表达式上下文还是运行时上下文,即在编译时是否已知函数的所有参数.
我希望答案是"是",但简单的检查表明情况并非如此.
constexpr
bool f(int) noexcept
{
return true;
}
constexpr
bool g(int)
{
return true;
}
static_assert(noexcept(f(1)));
static_assert(noexcept(g(2))); // comment this line to check runtime behaviour
#include <cassert>
#include <cstdlib>
int
main(int argc, char * [])
{
assert(noexcept(f(argc)));
assert(noexcept(g(argc)));
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
Sha*_*our 25
不可能不是这种情况,因为并非constexpr函数的每个inovocation都必须能够被评估为核心常量表达式的子表达式.我们只需要一个允许这个的参数值.因此,只要我们有一个不调用该分支的参数值,constexpr函数就可以包含一个throw语句.
这在C++ 14标准草案章节7.1.5constexpr说明符[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
Run Code Online (Sandbox Code Playgroud)
所以我们期望以下示例的输出:
#include <iostream>
constexpr int f(bool b) { return b ? throw 0 : 0; }
int main() {
std::cout << noexcept( f(1) ) << "\n"
<< noexcept( f(0) ) << "\n" ;
}
Run Code Online (Sandbox Code Playgroud)
是(看到它与gcc一起生活):
0
1
Run Code Online (Sandbox Code Playgroud)
通过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));
}
Run Code Online (Sandbox Code Playgroud)
上面的代码返回0,并警告该语句noexcept(f(512))无效.
在评论那个据说没有效果的陈述时,返回值会变为1.
编辑:已知的铿锵声
再次感谢@hvd也提供了这个链接,这是关于clang中关于代码中提到的代码的一个众所周知的错误.
从错误报告中引用:
在C++的书中,[expr.unary.noexcept] p3:
"如果在潜在评估的上下文中,表达式将包含对函数,成员函数,函数指针或不具有非抛出异常规范的成员函数指针的潜在评估调用,则noexcept运算符的结果为false (15.4),除非调用是常数表达式(5.19) ".
我们没有实现最后一个短语.
| 归档时间: |
|
| 查看次数: |
3006 次 |
| 最近记录: |