C++ 调用指向成员函数的指针后,noexcept运算符失败
这个MWE可能看起来是做作的,但失败的静态断言令人惊讶:C++ 调用指向成员函数的指针后,noexcept运算符失败,c++,clang,noexcept,C++,Clang,Noexcept,这个MWE可能看起来是做作的,但失败的静态断言令人惊讶: #include <utility> struct C { void f() noexcept { } using F = void(C::*)(); static constexpr F handler() noexcept { return &C::f; } void g() noexcept(noexcept((this->*handler())())) { } };
#include <utility>
struct C {
void f() noexcept { }
using F = void(C::*)();
static constexpr F handler() noexcept {
return &C::f;
}
void g() noexcept(noexcept((this->*handler())())) {
}
};
int main() {
static_assert(noexcept(std::declval<C>().g()));
}
#包括
结构C{
void f()noexcept{}
使用F=void(C::*)();
静态constexpr F handler()noexcept{
返回&C::f;
}
void g()noexcept(noexcept((this->*handler())()){
}
};
int main(){
静态断言(noexcept(std::declval().g());
}
魔盒链接:
我希望这对Clang有效,但对GCC无效,因为它们在运算符noexcept的上下文中对“this”的处理方式不同。鉴于您的
静态断言
没有字符串参数,您使用的是C++17。在C++17中,noexcept
成为类型系统的一部分。这意味着:
using F = void(C::*)();
此PMF不是noexcept
。调用它相当于调用noexcept(false)
成员函数。您需要将函数类型标记为noexcept
:
using F = void(C::*)() noexcept;
该更改允许您的代码编译:
#include <utility>
struct C {
void f() noexcept { }
using F = void(C::*)() noexcept;
static constexpr F handler() noexcept {
return &C::f;
}
void g() noexcept(noexcept((this->*handler())())) {
}
};
int main() {
static_assert(noexcept(std::declval<C>().g()));
}
#包括
结构C{
void f()noexcept{}
使用F=void(C::*)()无例外;
静态constexpr F handler()noexcept{
返回&C::f;
}
void g()noexcept(noexcept((this->*handler())()){
}
};
int main(){
静态断言(noexcept(std::declval().g());
}
f
是noexcept
,但指向它的指针不是。因此,在g
的定义中,这个->*处理程序()
返回的PMF不是noexcept
(即使您碰巧返回的MF地址是noexcept
,所以当您通过编写调用它时(这个->*处理程序())()
那么您调用的函数不是noexcept
,因此那里的noexcept
子句返回false
将
noexcept
添加到第5行的末尾,它就起作用了。你的问题是什么?如果其中一个答案回答了你的问题,你可以接受。如果两个答案都没有回答你的问题,你能解释一下为什么,以便我们可以改进我们的答案吗?很抱歉,耽搁了这么久;我对答案不满意,但我会接受一个,因为他们回答了问题问题的措辞。然而,在我的情况下,“f”是库用户传递的模板参数,因此我需要查询函数类型的noexcept ness以正确声明指向成员函数的指针的noexcept说明符。不幸的是,即使我将noexcept添加到类型别名中,它也不会编译,因为我的F别名已模板化,这会导致内部编译器错误或者,我会发布一个关于这个的叮当声。