C++中noexcept(f())标记函数g()是否生效的技术问询
咱们先直接给结论:你代码里的g()会被标记为noexcept(true),也就是第一种可能性是正确的。接下来咱们拆解背后的逻辑,以及如何主动控制这两种行为:
核心逻辑:noexcept的判断依据
noexcept(...)括号里的参数必须是常量表达式,编译器会在编译期对这个表达式求值,根据结果决定函数的noexcept状态:
- 表达式求值为
true→ 函数标记为noexcept(true) - 表达式求值为
false→ 函数标记为noexcept(false)
回到你的代码:
constexpr bool f() { return true; } void g() noexcept(f()) { f(); }
这里的f()是constexpr函数,在noexcept(f())这个常量表达式上下文中调用时,编译器会直接在编译期计算出它的返回值是true。关键要明白:noexcept()运算符判断的是传入的表达式本身是否会在编译期确定不抛出异常,而不是判断函数f本身有没有noexcept标记。
因为constexpr函数在常量表达式上下文里调用时,编译器会强制确保它不会抛出任何异常(否则编译会直接报错),所以f()这个表达式的结果是确定的true,因此g()会被标记为noexcept。
如何主动选择两种行为
1. 让函数标记为noexcept(第一种行为)
保持你当前的写法即可:在noexcept()中调用一个能被编译期求值的constexpr函数,只要这个函数的返回值是true,编译器就会把目标函数标记为noexcept。
你也可以更显式地定义编译期常量来实现:
constexpr bool safe_flag = true; void g() noexcept(safe_flag) { ... }
只要safe_flag是编译期确定的true,效果和你的原代码完全一致。
2. 让函数不标记为noexcept(第二种行为)
如果你想让g()的noexcept状态依赖于编译器对f()调用是否可能抛异常的判断(而不是编译期常量值),可以通过双层noexcept来实现:
bool f() { return true; } // 无noexcept标记 void g() noexcept(noexcept(f())) { f(); }
这里内层的noexcept(f())是一个运算符,用来判断f()这个调用是否会被编译器认为不会抛出异常——因为f没有标记noexcept,编译器无法确定它不会抛异常,所以内层运算符返回false,最终g()会被标记为noexcept(false)。
哪怕f是constexpr函数,只要你用这种双层noexcept的写法,也会得到同样的结果(因为f本身没有noexcept标记)。
内容的提问来源于stack exchange,提问作者Roxanne

