【问题标题】:noexcept operator fails after calling pointer-to-member functionnoexcept 运算符在调用指向成员函数后失败
【发布时间】:2018-03-24 23:50:18
【问题描述】:

这个 MWE 可能看起来做作,但失败的 static_assert 仍然令人惊讶:

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

魔杖链接:https://wandbox.org/permlink/a8HSyfuyX1buGrbZ

我希望这适用于 Clang 但不适用于 GCC,因为它们在 operator noexcept 的上下文中对“this”的处理不同。

【问题讨论】:

  • 你的问题是什么?
  • 如果其中一个答案回答了您的问题,您可以接受。如果两者都没有回答您的问题,您能解释一下原因,以便我们改进答案吗?
  • 抱歉拖了这么久;我对答案不满意,但我会接受一个,因为他们按措辞回答问题。但是,在我的例子中,“f”是库用户传递的模板参数,因此我需要查询函数类型的 noexcept-ness 以正确声明指向成员函数的指针的 noexcept 说明符。不幸的是,即使我将 noexcept 添加到类型别名,它也不会编译,因为我的 F 别名是模板化的,这会导致内部编译器错误。我将发布一个关于此的 Clang 错误。

标签: c++ clang noexcept


【解决方案1】:

看到您的 static_assert 没有字符串参数,您使用的是 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()));
}

On Godbolt

【讨论】:

    【解决方案2】:

    fnoexcept,但指向它的指针不是。所以在g的定义中,this-&gt;*handler()返回一个不是noexcept的PMF(即使你碰巧返回了一个noexcept的MF的地址,所以当你调用通过编写(this-&gt;*handler())(),那么您正在调用一个不是noexcept 的函数,因此那里的noexcept 子句返回false

    在第 5 行末尾添加noexcept 即可。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-11
      • 2023-03-05
      • 1970-01-01
      • 2013-01-26
      • 1970-01-01
      • 1970-01-01
      • 2019-09-18
      相关资源
      最近更新 更多