C++条件表达式中调用[[noreturn]]抛异常函数编译失败如何解决
问题根因
C++ 标准对条件运算符(?:)的操作数类型匹配有明确约束:仅当两个操作数类型可隐式转换,或其中一个操作数是 throw 表达式,或两个操作数均为 void 类型时,表达式才合法。[[noreturn]]、inline 都只是给编译器的优化/提示属性,不会修改函数本身的返回类型:你定义的 foo() 返回值类型始终是 void,不属于 throw 表达式,因此和另一侧的 int 类型操作数匹配时,直接触发类型校验报错。
实现方案
针对你做语言转译器、需要在条件表达式分支里调用始终抛异常函数的场景,有两种无额外开销的实现方式:
- 直接用逗号表达式包裹调用,让操作数符合throw表达式的语法要求
不需要额外写辅助逻辑,转译生成代码时直接把对应分支写成(foo(), throw std::exception())即可。逗号表达式会先执行foo()(函数本身已经抛出异常,后面的throw永远不会实际执行),整个操作数属于合法的throw表达式,完全通过编译,示例:int b = true ? 1 : (foo(), throw std::exception()); - 定义通用的泛型noreturn辅助函数,适配任意类型的条件分支
如果不想每次都写冗余的throw,可以提前定义一个泛型辅助函数,返回类型由模板参数指定,适配另一侧操作数的类型:
使用时直接根据另一侧操作数的类型指定模板参数即可,比如另一侧是template<typename T> [[noreturn]] T throw_default() { // 这里放你需要的默认抛异常逻辑,比如调用foo() foo(); // 后续代码永远不会执行,仅用于满足编译器的返回值类型检查 throw std::exception(); }int就写throw_default<int>(),另一侧是std::string就写throw_default<std::string>(),编译器识别到[[noreturn]]属性后不会生成多余冗余代码,运行时开销为0:int b = true ? 1 : throw_default<int>();
注意:不要试图靠
[[noreturn]]属性让编译器自动识别void返回值函数的never return语义,C++标准从未将noreturn属性纳入条件运算符的类型匹配规则,所有编译器都会按void类型做校验,直接调用必然报错。
内容的提问来源于stack exchange,提问作者burnedWood
相关产品推荐
相关产品推荐

