The following code compiles and works fine in gcc:
#include <barrier>
#include <functional>
#include <iostream>
struct Class {
Class() : barrier(1, [this]() { onCompletion(); }) { barrier.arrive_and_wait(); }
void onCompletion() { std::cout << "Completed." << std::endl; }
std::barrier<std::function<void()>> barrier;
};
int main() { Class(); }
However, it fails to even compile in MSVC. I have found dozens of similar questions proposing solutions that do not even compile in MSVC.
So I am wondering, is std::barrier
at all usable (as a member variable, calling a member function on completion) in MSVC?
The following code compiles and works fine in gcc:
#include <barrier>
#include <functional>
#include <iostream>
struct Class {
Class() : barrier(1, [this]() { onCompletion(); }) { barrier.arrive_and_wait(); }
void onCompletion() { std::cout << "Completed." << std::endl; }
std::barrier<std::function<void()>> barrier;
};
int main() { Class(); }
However, it fails to even compile in MSVC. I have found dozens of similar questions proposing solutions that do not even compile in MSVC.
So I am wondering, is std::barrier
at all usable (as a member variable, calling a member function on completion) in MSVC?
1 Answer
Reset to default 2Unsure of why exactly only MSVC has this exact behaviour while other compilers have not, however, the issue seems to be related to some validated constraints due to usage of std::function.
See https://en.cppreference/w/cpp/thread/barrier, "Template Parameter", specifically:
"CompletionFunction ... std::is_nothrow_invocable_v<CompletionFunction&> must be true". This seems to be "false" for std::function<void()> on MSVC.
Now, on MSVC, std::is_nothrow_invocable_v<std::function<void()>>
is "false", at least on my machine. This is reflected in the actual compile-error I get, trying to setup a barrier like that:
error C2338: static_assert failed: 'N4950 [thread.barrier.class]/5: is_nothrow_invocable_v<CompletionFunction&> shall be true'
Looking at cpp-reference again for the definition of std::function::operator(), it seems it does indeed not specify "noexcept" - which is logical, otherwise you couldn't pass exceptions through an std::function at all. So, just by that, my assumption is that your code should not compile on any compiler. So it at least seems that MSVC is correct due to the specification, whereas GCC is likely an oversight/bug.
I have never worked with barrier, so I don't know what alternative you are supposed to use. If you don't need a capture, probably just a function-pointer. If you do need a capture, maybe just use a custom wrapper around std::function that uses specifies "noexcept" in its call-operator? The latter is just throwing points around, doing so could potentially be dangerous, so a different solution (if existing) should probably be found.
std::barrier<std::move_only_function<void() noexcept>> barrier;
andbarrier(1, [this]() noexcept { onCompletion(); })
- That seems to work everywhere. – Ted Lyngmo Commented Mar 18 at 19:46std::move_only_function
was introduced in C++23. But my project allows me to use that - thanks! – bers Commented Mar 19 at 6:38