最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Is std::barrier usable in C++ as member variable with a completion function calling a member function? - Stack Overflow

programmeradmin3浏览0评论

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?

Share Improve this question asked Mar 18 at 17:53 bersbers 5,9832 gold badges46 silver badges86 bronze badges 3
  • 2 Workaround: Make it std::barrier<std::move_only_function<void() noexcept>> barrier; and barrier(1, [this]() noexcept { onCompletion(); }) - That seems to work everywhere. – Ted Lyngmo Commented Mar 18 at 19:46
  • Great idea. "everywhere" is relative, though, since std::move_only_function was introduced in C++23. But my project allows me to use that - thanks! – bers Commented Mar 19 at 6:38
  • Great! You are welcome! – Ted Lyngmo Commented Mar 19 at 6:42
Add a comment  | 

1 Answer 1

Reset to default 2

Unsure 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.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论