c++c++20unique-ptrbarrier

Using std::unique_ptr<std::barrier<void()>> in a class - Error occured when calling arrive_and_wait()


Because I can't use directly std::barrier in a class, I decided to use std::unique_ptr in order to dynamically allocate it. That will also allow me to dynamically change the expected number of thread.

Here is a sample snippet of my class.

class MyClass
{
public:
    MyClass()
    : la_barriere( std::make_unique< std::barrier<void()> >( 3, [this](){
            callback1();callback2();
        } ) )
    { /*empty constructor*/}

    void run(){ la_barriere->arrive_and_wait(); }
private:
    void callback1(){ std::cout << "callback1()\n"; }
    void callback2(){ std::cout << "callback2()\n"; }

    std::unique_ptr< std::barrier<void()> > la_barriere;
};

int main()
{
    MyClass test;

    std::jthread t1( &MyClass::run, &test );
    std::jthread t2( &MyClass::run, &test );
    std::jthread t3( &MyClass::run, &test );
    return 0;
}

I getting these errors when I try to compile:

g++.exe -Wall -fexceptions -g -std=c++20  -c D:\Programmes\barrier_completion_function\main.cpp -o obj\Debug\main.o
g++.exe  -o bin\Debug\barrier_completion_function.exe obj\Debug\main.o   
In file included from D:\Programmes\barrier_completion_function\main.cpp:3:
C:/MinGW/include/c++/13.1.0/barrier: In instantiation of 'class std::__tree_barrier<void()>':
C:/MinGW/include/c++/13.1.0/barrier:216:21:   required from 'class std::barrier<void()>'
D:\Programmes\barrier_completion_function\main.cpp:15:28:   required from here
C:/MinGW/include/c++/13.1.0/barrier:99:20: error: data member 'std::__tree_barrier<void()>::_M_completion' invalidly declared function type
   99 |       _CompletionF _M_completion;
      |                    ^~~~~~~~~~~~~
In file included from C:/MinGW/include/c++/13.1.0/bits/std_thread.h:43,
                 from C:/MinGW/include/c++/13.1.0/barrier:48:
C:/MinGW/include/c++/13.1.0/bits/unique_ptr.h: In instantiation of 'std::__detail::__unique_ptr_t<_Tp> std::make_unique(_Args&& ...) [with _Tp = barrier<void()>; _Args = {int, MyClass::MyClass()::<lambda()>}; __detail::__unique_ptr_t<_Tp> = __detail::__unique_ptr_t<barrier<void()> >]':
D:\Programmes\barrier_completion_function\main.cpp:10:60:   required from here
C:/MinGW/include/c++/13.1.0/bits/unique_ptr.h:1070:30: error: no matching function for call to 'std::barrier<void()>::barrier(int, MyClass::MyClass()::<lambda()>)'
 1070 |     { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
      |                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:/MinGW/include/c++/13.1.0/barrier:238:7: note: candidate: 'std::barrier<_CompletionF>::barrier(std::ptrdiff_t, _CompletionF) [with _CompletionF = void(); std::ptrdiff_t = long long int]'
  238 |       barrier(ptrdiff_t __count, _CompletionF __completion = _CompletionF())
      |       ^~~~~~~
C:/MinGW/include/c++/13.1.0/barrier:238:47: note:   no known conversion for argument 2 from 'MyClass::MyClass()::<lambda()>' to 'void (*)()'
  238 |       barrier(ptrdiff_t __count, _CompletionF __completion = _CompletionF())
      |                                  ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I want to allocate std::barrier on the heap, dynamically change the expected thread that must wait and the supplied completionFunction being called after the each phase


Solution

  • This has nothing to do with the use of std::unique_ptr.

    The problem is that void() is not a valid template argument for std::barrier. Maybe you want std::barrier<std::function<void()>> instead.

    The template argument must be a function object type that is move-constructible and destructible, which function types like void() are not.