38

In C++17 noexcept has been added to the type system:

void r1( void (*f)() noexcept ) { f(); }
void foo() { throw 1; }

int main()
{
    r1(foo);
}

The latest versions of GCC and Clang in C++17 mode reject the call r1(foo), because void (*)() cannot be implicitly converted to void (*)() noexcept.

But with std::function instead:

#include <functional>

void r2( std::function<void() noexcept> f ) { f(); }
void foo() { throw 1; }

int main()
{
    r2(foo);
}

Clang accepts the program, apparently ignoring the noexcept specifier; and g++ gives a strange error regarding std::function<void() noexcept>.

What is the correct behaviour for this second program in C++17?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
M.M
  • 138,810
  • 21
  • 208
  • 365
  • If `noexcept` is now considered to be a part of the type, then `void () noexcept` is different from `void ()`, hence this is ill-formed. Not including exception specification as part of the function's signature, unlike Java, was something that I always thought C++ got wrong. Good to see that this is now being corrected. – Sam Varshavchik Dec 22 '16 at 23:40
  • 5
    The behavior is that it should complain about an incomplete type. `std::function` is partially specialized for `R(Args...)` only, not `R(Args...) noexcept`. – T.C. Dec 23 '16 at 00:28
  • @T.C. ok, correct behaviour by g++ 7 then. Could you write that comment into an answer? – M.M Dec 23 '16 at 00:34
  • Your first snippet is invalid even in C++14: https://timsong-cpp.github.io/cppwp/n4140/except.spec#5 – T.C. Dec 23 '16 at 09:28

1 Answers1

34

std::function's definition hasn't changed in the current working draft:

template<class T>
class function; // not defined

template<class R, class... ArgTypes>
class function<R(ArgTypes...)> {
    /* ... */
};

Since void() noexcept doesn't match the partial specialization, std::function<void() noexcept> is an incomplete type. Both Clang and GCC trunk diagnose this accordingly.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • 16
    As best as I can tell, `std::function` has not been updated to include a partial specialization for `R(ArgTypes...) noexcept` in C++17 nor even leading into C++20. Is this something that the standards committee has ever addressed (to public knowledge about the matter)? MSVC++, GCC, and Clang all enforce the `noexcept` signature (if present) when using `target`, but you **can't** use it as part of the class template's signature. To me that seems to violate the whole notion of `noexcept` being part of the function signature. Thanks for any update/feedback on this. – monkey0506 Apr 15 '19 at 22:55