VC++ 2022中noexcept运算符相关编译问题咨询
VC++ 2022中noexcept运算符的编译疑问及解答
测试代码
// noexcept测试基类 class MyNoExcept { public: void Func() noexcept {} void Func1() {} }; // noexcept测试派生类 class MyNoExcept2 : public MyNoExcept { public: void Func2() noexcept(noexcept(MyNoExcept::Func())) { static_assert(noexcept(MyNoExcept::Func()), "MyNoExcept::Func()必须是noexcept"); } // Func1的noexcept声明写法错误! void Func3() noexcept(noexcept(static_cast<MyNoExcept*>(this)->Func1)) { static_assert(noexcept(static_cast<MyNoExcept*>(this)->Func1), "MyNoExcept::Func1()必须是noexcept"); } }; // 测试函数 void TestNoexcept() { MyNoExcept2 m; m.Func2(); // 编译错误 C2056: 非法表达式 if constexpr (noexcept(MyNoExcept::Func())) { printf("MyNoExcept::Func()是noexcept\n"); } m.Func3(); }
疑问
- 显然
noexcept(MyNoExcept::Func())是编译期表达式,为何constexpr if语句无法编译?
- 显然
- Func3中对无参函数MyNoExcept::Func1的noexcept声明及static_assert使用了错误写法,但代码仍能编译并给人安全的假象。预期是
if constexpr (noexcept(MyNoExcept::Func()))可正常编译,且void Func3() noexcept(noexcept(static_cast<MyNoExcept*>(this)->Func1))会触发编译错误。
- Func3中对无参函数MyNoExcept::Func1的noexcept声明及static_assert使用了错误写法,但代码仍能编译并给人安全的假象。预期是
解答
问题1:constexpr if中noexcept表达式编译失败
VC++ 2022对非模板上下文的if constexpr有特殊限制:它要求条件表达式不仅是常量表达式,还要满足“在当前上下文可被编译器明确判定为常量操作”。虽然MyNoExcept::Func()是空实现且标记为noexcept,但VC++在非模板函数的if constexpr中,没有正确识别该函数调用属于常量表达式允许的操作。
两种可行的解决方式:
- 将
TestNoexcept改为模板函数,让表达式处于依赖模板参数的上下文,此时编译器会正确处理:template<typename T> void TestNoexcept() { MyNoExcept2 m; m.Func2(); if constexpr (noexcept(MyNoExcept::Func())) { printf("MyNoExcept::Func()是noexcept\n"); } m.Func3(); } - 直接判断函数类型的noexcept属性,省略函数调用括号,这种写法更简洁且能绕过VC++的限制:
if constexpr (noexcept(MyNoExcept::Func)) { printf("MyNoExcept::Func()是noexcept\n"); }
问题2:错误写法未触发编译错误
你在Func3中写的static_cast<MyNoExcept*>(this)->Func1是取成员函数的指针,而非调用函数。noexcept(...)在这里判断的是“获取函数指针”这个操作是否会抛出异常——而取成员函数指针的操作本身永远是noexcept的,所以noexcept(...)的结果恒为true,导致static_assert不会触发,函数的noexcept声明也错误地标记为noexcept。
正确写法必须加上函数调用的括号,让noexcept判断的是函数调用的异常属性:
void Func3() noexcept(noexcept(static_cast<MyNoExcept*>(this)->Func1())) { static_assert(noexcept(static_cast<MyNoExcept*>(this)->Func1()), "MyNoExcept::Func1()必须是noexcept"); }
此时编译器会正确识别Func1()没有noexcept修饰,触发static_assert的编译错误,函数的noexcept声明也会匹配Func1()的实际异常属性。
内容的提问来源于stack exchange,提问作者Boris Bromberg
相关产品推荐
相关产品推荐

