4

Why does the noexcept operator take an expression rather than a function signature/declaration?

Consider the following dummy example:

#include <string>

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

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

It won't compile because method1 has a non-constexpr expression in its noexcept, but why do I need to put an expression in there in the first place?

All I want to do is tell the compiler that method1 is noexcept iff an invocation of strProcessor with a succesfully constructed string is noexcept (which it is).

So why not noexcept(void strProcessor(const std::string&))?

Another similar dummy example:

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

Here I'd like to say method2 is noexcept iff invoking method1 on a succesfully constructed instance of Type is noexcept (which it is in this case), but Type isn't even complete at the point where method2 id defined.

Please explain if my understanding of this feature is wrong.

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • Well there's flexibility here as then you can do more clever things than simply naming a function. The expression won't be evaluated, so you can use `declval` and friends to avoid any side-effects and so forth. I don't really understand the error though as I'm not too hot on either `noexcept` or `constexpr`. – Lightness Races in Orbit Jul 27 '15 at 13:35

2 Answers2

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

The first one is the noexcept specifier, which specifies whether or not method1() is noexcept.

The nested one is the noexcept operator, which checks whether strProcessor() is noexcept when called with "".

Your second case is a bit tricky : Type is still incomplete at the point we'd like to use method1() inside noexcept. I've come to the following workaround, abusing a pointer-to-member :

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

However, I don't think there's a case where you could only deduce method2()'s noexcept specification from that of method1().

Quentin
  • 62,093
  • 7
  • 131
  • 191
2

If you want some syntactic sugar when checking the noexceptness of a function, you can use an auxiliary function like so:

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

And apply thusly:

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

Demo.

Columbo
  • 60,038
  • 8
  • 155
  • 203