How could I make this working ?
#include <iostream>
#include <thread>
using namespace std;
int main()
{
auto thr = []<typename PrintType>( PrintType &p )
{
cout << p << endl;
};
string str = "hello world";
jthread jt( thr, ref( str ) );
}
I don't even understand what's the issue here.
This is what clang 13 on Windows says:
In file included from test.cpp:2:
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\thread:55:9: error: no matching function for call to 'invoke'
_STD invoke(_STD move(_STD get<_Indices>(_Tup))...);
^~~~~~~~~~~
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\yvals_core.h:1385:20: note: expanded from macro '_STD'
#define _STD ::std::
^
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\thread:62:17: note: in instantiation of function template specialization 'std::thread::_Invoke<std::tuple<(lambda at test.cpp:8:13), std::reference_wrapper<std::basic_string<char>>>, 0ULL, 1ULL>' requested here
return &_Invoke<_Tuple, _Indices...>;
^
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\thread:302:19: note: in instantiation of function template specialization 'std::thread::_Start<(lambda at test.cpp:8:13) &, std::reference_wrapper<std::basic_string<char>>>' requested here
_Impl._Start(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...);
^
test.cpp:13:10: note: in instantiation of function template specialization 'std::jthread::jthread<(lambda at test.cpp:8:13) &, std::reference_wrapper<std::basic_string<char>>, 0>' requested here
jthread jt( thr, ref( str ) );
^
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\type_traits:1482:19: note: candidate template ignored: substitution failure [with _Callable = (lambda at test.cpp:8:13), _Ty1 = std::reference_wrapper<std::basic_string<char>>, _Types2 = <>]: no matching function for call to '_Call'
_CONSTEXPR17 auto invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept(
^
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\type_traits:1476:19: note: candidate function template not viable: requires single argument '_Obj', but 2 arguments were provided
_CONSTEXPR17 auto invoke(_Callable&& _Obj) noexcept(noexcept(static_cast<_Callable&&>(_Obj)()))
^
1 error generated.
CodePudding user response:
The problem here is kinda unsolvable as long as we insist on passing thr
lambda to jthread
constructor. This snippet
auto thr = []<typename PrintType>( PrintType &p )
{
cout << p << endl;
};
string str = "hello world";
jthread jt(thr, str);
is going to fail, because you can't bind non-const reference to a temporary resulting within jthread
constructor (Note: const PrintType& hp
would work, but I assume, it would not be what OP wants).
std::ref
would work with non-templated lambda:
auto thr = [](std::string& p)
{
std::cout << p << std::endl;
};
std::string str = "hello world";
std::thread jt( thr, std::ref(str) );
But it won't work with templated lambda (becauseauto thr = [](auto& p)
will just try to bind non-const lvalue reference to temporary object of reference_wrapper
type).
The only solution I can think of is to pass lambda with closures directly to thread constructor:
auto thr = []<class Type>(Type& p)
{
std::cout << p << std::endl;
};
std::string str = "hello world";
std::thread jt([&str, &thr]() { thr(str); });
CodePudding user response:
TLDR:
jthread jt(&decltype(thr)::operator()<std::string>, thr, ref(str));
The problem you are having is due to a substitution of PrintType
by std::reference_wrapper
, which is not recognised as a valid argument for operator<<
. You expect the compiler to do an implicit conversion from std::reference_wrapper
to std::string&
when receiving it as an argument, but the compiler does not expect an std::string&
there. It expects std::reference_wrapper
.
/opt/compiler-explorer/gcc-11.2.0/include/c /11.2.0/thread: In instantiation of 'static std::thread std::jthread::_S_create(std::stop_source&, _Callable&&, _Args&& ...) [with _Callable = main()::<lambda(PrintType&)>&; _Args = {std::reference_wrapper<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >}]':
As you can see, you don't end up with std::string&
as an argument, but with a wrapper: std::reference_wrapper<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >
.
This code compiles:
#include <thread>
#include <iostream>
using namespace std;
int main()
{
auto thr = [](const std::string &p)
{
cout << p << endl;
};
string str = "hello world";
jthread jt(thr, ref( str ));
}
So, the logical solution would be to force the compiler to instantiate the template with the right type:
#include <thread>
#include <iostream>
#include <type_traits>
using namespace std;
int main()
{
auto thr = []<typename PrintType>(PrintType& p)
{
cout << p << endl;
};
string str = "hello world";
// explicitly instantiating via a pointer to member function
jthread jt(&decltype(thr)::operator()<std::string>, thr, ref(str));
}