1

I have a problem with preservation of noexcept specifier in std::bind, using C++17. In GCC and Clang is not preserved, but in MSVC it is. It seems that using bind with a function with noexcept specifier, the resulting object doesn't preserve it, considering always that it isn't noexcept.

Having a function like:

void f(int) noexcept;

And now creating a callable with std::bind on it:

auto g = std::bind(f,5);

It can be seen that noexcept behaviour is different between f and g when executing in GCC and Clang (using C++17 mode)

std::cout << noexcept(f(5)); //prints 1, ok, as expected
std::cout << noexcept(g()); //prints 0, WRONG!!

As mentioned at the beginning, MSVC is the only with (in my opinion) consistent behaviour. Reading the standard specification doesn't mention anything about that, so maybe this behaviour is not specified So, is this a normal behaviour because the lack of specification in the standard or is a bug?

Is any way to force the "noexcept" specifier when using bind?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • You probably shouldn't use `std::bind` if you are in C++17 mode. You can use a lambda instead. – user17732522 Mar 30 '22 at 07:54
  • I know this could be a solution in some cases, in fact is the way I have resolved it for some cases, but because the genericity of the code I'm writting, this can't be always achieved. Thanks – Daniel Barrientos Mar 30 '22 at 08:12
  • Do you need to exactly support uses of `std::bind`? or can you write a intermediate function and use that one rather than `std::bind`? – Afshin Mar 30 '22 at 09:12
  • Hi Afshin. I can use (in fact I'm using it) lambda as a workaroung for some cases. The thing is that I need to know de exception specifier (via noexcept() or std::is_nothrowable_invocable) to take some decissions inside a templated library. But, I don't want to force the users to know about this fact, because any callable can be passed as argument to this library interface. But is clear now that this seems to be the normal behaviour for std::bind, so I will need to refactor the code as possible. Thanks – Daniel Barrientos Mar 30 '22 at 09:26

1 Answers1

2

If you can use C++20, then you can just use std::bind_front, which not only has better performance than std::bind, but the operator() of the perfect forwarding call wrapper it returns is noexcept if the std::invoke expression it calls is noexcept (in other words, it preserves the exception specification of the underlying call operator), so the following static_assert can pass for all three compilers

#include <functional>

void f(int) noexcept;

auto g = std::bind_front(f,5);

static_assert(noexcept(f(5)));
static_assert(noexcept(g()));

Demo

康桓瑋
  • 33,481
  • 5
  • 40
  • 90
  • Thanks. It would be a solution I a could use C++20, but it's not possible right now, and this is the reason a specified that i'm using C++17 at the beginning. But thank you anyway – Daniel Barrientos Mar 30 '22 at 08:41