C++中向noexcept传递函数调用表达式的作用及两种声明的区别
C++ noexcept相关问题解答
1. 向noexcept传递函数调用表达式的作用
noexcept(常量表达式)是C++11引入的带参数异常规范,括号内的常量表达式会在编译期隐式转换为bool类型:
- 结果为
true:声明当前函数不会抛出异常,运行期如果抛出会直接调用std::terminate终止程序 - 结果为
false:声明当前函数允许抛出异常
如果传递的是函数调用表达式,注意这个调用不会在运行期执行,仅会在编译期对表达式的结果求值,用来确定异常规范的开闭状态。
2. 两种函数声明的核心区别
先明确一个常见误区:你提到的「第一种写法中bar的异常规范与foo一致」是错误的,两者的实际行为完全不同:
第一种写法
bool foo(int){return 0;} void bar()noexcept(foo){}
这里括号内的foo是函数名,属于函数类型左值,在bool语境下会先隐式转换为函数指针,再转为bool值:因为函数地址必然非空,所以转换结果固定为true,等价于noexcept(true),即bar被声明为不会抛出异常。这个结果和foo本身的返回值、异常规范没有任何关联。
第二种写法
void bar()noexcept(foo(10)){}
这里括号内是foo(10)的函数调用表达式,需要满足编译期常量要求:
- 如果
foo没有被声明为constexpr,这个表达式无法在编译期求值,代码直接编译报错 - 如果
foo是constexpr函数,foo(10)的返回值是0,隐式转换为false,等价于noexcept(false),即bar允许抛出异常
两个疑问的解答
1. noexcept(noexcept(foo(10)))的含义
这里涉及两种完全不同的noexcept用法:
- 内层的
noexcept(foo(10))是noexcept运算符,作用是编译期判断foo(10)这个调用是否会抛出异常,返回一个bool类型的常量表达式:foo被声明为不抛异常就返回true,否则返回false - 外层的
noexcept(...)是异常规范,接收内层运算符返回的bool值作为参数
所以整个写法的作用是:让bar的异常规范和foo(int)的调用异常规范完全对齐,foo不会抛则bar也不会抛,foo允许抛则bar也允许抛。
2. 两种bar的声明是否完全相同?
完全不同,差异总结:
- 第一种写法必然合法,等价于
noexcept(true),bar不允许抛出异常 - 第二种写法在
foo非constexpr时直接编译失败;foo是constexpr时等价于noexcept(false),bar允许抛出异常 - 两种写法的异常规范状态完全相反,不存在等价的场景
内容的提问来源于stack exchange,提问作者Itachi Uchiwa
相关产品推荐
相关产品推荐

