C++ 调用指向成员函数的指针后,noexcept运算符失败

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())())) { } };

这个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())())) {
  }
};

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别名已模板化,这会导致内部编译器错误或者,我会发布一个关于这个的叮当声。