使用noexcept运算符来链接noexcept声明

4
为什么 `noexcept` 运算符需要接受表达式而不是函数签名或声明?
考虑以下虚构的示例:
#include <string>

void strProcessor(const std::string& str) noexcept(true) { };

struct Type{
  void method1() noexcept(strProcessor("")) { //Error: Call to nonconstexpr function
     strProcessor("");
  }
};

它无法编译,因为method1在其noexcept中具有非constexpr表达式,但是我为什么需要首先在那里放置一个表达式?

我想要做的就是告诉编译器 method1 是noexcept,当且仅当使用成功构造的字符串调用strProcessor时也是noexcept(它确实是)。

那么为什么不是noexcept(void strProcessor(const std :: string&))呢?

另一个类似的虚拟例子:

struct Type{
   Type(bool shouldThrow=false) noexcept(false) { if(shouldThrow) throw "error"; };
   void method1() noexcept(true) {};
   void method2() noexcept(noexcept(Type().method1())) { method1(); };
}

我想说的是,method2 只有在成功构造 Type 的实例时调用 method1 是无异常的时才是 noexcept (在这种情况下确实是这样),但在定义 method2 时,Type 甚至还没有完全被定义。

如果我对此特性的理解有误,请解释一下。


嗯,在这里有一定的灵活性,因为你可以做比仅仅命名一个函数更聪明的事情。表达式不会被评估,所以你可以使用 declval 和相关的内容来避免任何副作用等。尽管我对于 noexceptconstexpr 都不是很熟悉,但我并不真正理解这个错误。 - Lightness Races in Orbit
2个回答

13
void method1() noexcept(noexcept(strProcessor(""))) {
//   Second 'noexcept'  ^^^^^^^^^                ^

第一个是noexcept specifier,它指定method1()是否为noexcept

嵌套的是noexcept operator,它检查strProcessor()使用""时是否为noexcept

你的第二个情况有点棘手:在我们想要在noexcept中使用method1()的那一点上,Type仍然是不完整的。我想到了以下的解决方法,滥用了一个指向成员的指针:

void method2() noexcept(noexcept(
    (std::declval<Type>().*&Type::method1)()
)) {};

然而,我认为没有这样的情况,只能通过method1()noexcept来推断出method2()noexcept说明。


谢谢!你能修复第二个例子吗? - Petr Skocik

2

如果你想在检查函数的noexcept时使用一些语法糖,可以使用辅助函数,如下所示:

template <typename R, typename... Params>
constexpr bool is_noexcept(R(*p)(Params...)) {
    return noexcept(p(std::declval<Params>()...));
}

并这样申请:

void method1() noexcept(is_noexcept(strProcessor)) …

Demo.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接