Compilation Error with Asio-GRPC and MSVC 14.39 - work_tracking_completion_handler.hpp(54,98): error C2182: 'work_': this use of 'void' is not valid
Closed this issue · 3 comments
- msvc : 143(14.39)
- C++ : 20
- boost : 1.85, 1.86
- grpc : 1.60
- asio-grpc : 3.2
I'm encountering a compilation error when attempting to use Asio-GRPC in combination with MSVC 14.39, C++20, Boost 1.85/1.86, and grpc 1.60. The following code snippet results in an error during compilation:
grpc::Status status;
helloworld::Greeter::Stub stub{grpc::CreateChannel(host, grpc::InsecureChannelCredentials())};
agrpc::GrpcContext grpc_context;
asio::co_spawn(
grpc_context,
[&]() -> asio::awaitable<void>
{
using RPC = example::AwaitableClientRPC<&helloworld::Greeter::Stub::PrepareAsyncSayHello>;
grpc::ClientContext client_context;
helloworld::HelloRequest request;
request.set_name("world");
helloworld::HelloReply response;
status = co_await RPC::request(grpc_context, stub, client_context, request, response);
std::cout << status.ok() << " response: " << response.message() << std::endl;
},
example::RethrowFirstArg{}
);
grpc_context.run();
the following compilation error is produced:`
D:\dev\asio-grpc\include\agrpc\detail\work_tracking_completion_handler.hpp(54,98): error C2182: 'work_': this use of 'void' is not valid
1>(compiling source file '../../../grpc/GrpcLeaderService.cpp')
1> D:\dev\asio-grpc\include\agrpc\detail\work_tracking_completion_handler.hpp(54,98):
1> the template instantiation context (the oldest one first) is
1> D:\dev\app\common\grpc\GrpcLeaderService.cpp(1291,53):
1> see reference to function template instantiation 'boost::asio::awaitable<T,Executor> agrpc::b::detail::ClientRPCUnaryBase<std::unique_ptr<grpc::ClientAsyncResponseReaderGrpc::ServiceTask,std::default_delete<grpc::ClientAsyncResponseReaderGrpc::ServiceTask>> Grpc::TaskService::Stub::PrepareAsyncPostRequestServiceTask(grpc::ClientContext *,const Grpc::ServiceTask &,grpc::CompletionQueue *),boost::asio::use_awaitable_t::executor_with_default<agrpc::b::BasicGrpcExecutor<std::allocator,1>>>::request<boost::asio::use_awaitable_t>(agrpc::b::GrpcContext &,StubT &,grpc::ClientContext &,const RequestT &,ResponseT &,CompletionToken &&)' being compiled
1> with
1> [
1> T=grpc::Status,
1> Executor=boost::asio::any_io_executor,
1> StubT=Grpc::TaskService::Stub,
1> RequestT=Grpc::ServiceTask,
1> ResponseT=Grpc::ServiceTask,
1> CompletionToken=boost::asio::use_awaitable_tboost::asio::any_io_executor
1> ]
1> D:\dev\asio-grpc\include\agrpc\client_rpc.hpp(134,24):
1> see reference to function template instantiation 'boost::asio::awaitable<T,Executor> agrpc::b::detail::async_initiate_sender_implementation<agrpc::b::detail::ClientUnaryRequestSenderInitiation,agrpc::b::detail::ClientUnaryRequestSenderImplementation<std::unique_ptr<grpc::ClientAsyncResponseReaderGrpc::ServiceTask,std::default_delete<grpc::ClientAsyncResponseReaderGrpc::ServiceTask>> Grpc::TaskService::Stub::PrepareAsyncPostRequestServiceTask(grpc::ClientContext *,const Grpc::ServiceTask &,grpc::CompletionQueue *)>,CompletionToken>(agrpc::b::GrpcContext &,const Initiation &,Implementation &&,CompletionToken &&)' being compiled
1> with
1> [
1> T=grpc::Status,
1> Executor=boost::asio::any_io_executor,
1> ResponseT=Grpc::ServiceTask,
1> CompletionToken=boost::asio::use_awaitable_tboost::asio::any_io_executor,
1> Initiation=agrpc::b::detail::ClientUnaryRequestSenderInitiationGrpc::ServiceTask,
1> Implementation=agrpc::b::detail::ClientUnaryRequestSenderImplementation<std::unique_ptr<grpc::ClientAsyncResponseReaderGrpc::ServiceTask,std::default_delete<grpc::ClientAsyncResponseReaderGrpc::ServiceTask>> Grpc::TaskService::Stub::PrepareAsyncPostRequestServiceTask(grpc::ClientContext *,const Grpc::ServiceTask &,grpc::CompletionQueue *)>
1> ]
1> D:\dev\asio-grpc\include\agrpc\detail\initiate_sender_implementation.hpp(60,22):
1> see reference to function template instantiation 'boost::asio::awaitable<T,Executor> boost::asio::async_initiate<CompletionToken,agrpc::b::detail::StatusSenderImplementationBase::Signature,agrpc::b::detail::SubmitSenderImplementationOperation,const Initiation&,Implementation>(agrpc::b::detail::SubmitSenderImplementationOperation &&,boost::asio::use_awaitable_t &,const Initiation &,Implementation &&)' being compiled
1> with
1> [
1> T=grpc::Status,
1> Executor=boost::asio::any_io_executor,
1> CompletionToken=boost::asio::use_awaitable_tboost::asio::any_io_executor,
1> Initiation=agrpc::b::detail::ClientUnaryRequestSenderInitiationGrpc::ServiceTask,
1> Implementation=agrpc::b::detail::ClientUnaryRequestSenderImplementation<std::unique_ptr<grpc::ClientAsyncResponseReaderGrpc::ServiceTask,std::default_delete<grpc::ClientAsyncResponseReaderGrpc::ServiceTask>> Grpc::TaskService::Stub::PrepareAsyncPostRequestServiceTask(grpc::ClientContext *,const Grpc::ServiceTask &,grpc::CompletionQueue *)>
1> ]
1> D:\dev\boost_lib\boost\asio\async_result.hpp(629,65):
1> see reference to function template instantiation 'boost::asio::awaitable<T,Executor> boost::asio::async_result<boost::asio::use_awaitable_t,agrpc::b::detail::StatusSenderImplementationBase::Signature>::initiate<Initiation,agrpc::b::detail::ClientUnaryRequestSenderInitiation,Implementation>(Initiation,boost::asio::use_awaitable_t,agrpc::b::detail::ClientUnaryRequestSenderInitiation,Implementation)' being compiled
1> with
1> [
1> T=grpc::Status,
1> Executor=boost::asio::any_io_executor,
1> Initiation=agrpc::b::detail::SubmitSenderImplementationOperation,
1> ResponseT=Grpc::ServiceTask,
1> Implementation=agrpc::b::detail::ClientUnaryRequestSenderImplementation<std::unique_ptr<grpc::ClientAsyncResponseReaderGrpc::ServiceTask,std::default_delete<grpc::ClientAsyncResponseReaderGrpc::ServiceTask>> Grpc::TaskService::Stub::PrepareAsyncPostRequestServiceTask(grpc::ClientContext *,const Grpc::ServiceTask &,grpc::CompletionQueue *)>
1> ]
1> D:\dev\boost_lib\boost\asio\impl\awaitable.hpp(402,8):
1> while compiling class template member function 'auto boost::asio::detail::awaitable_frame_base::await_transform(Function,std::enable_if<std::is_convertible<result_of<Function(boost::asio::detail::awaitable_frame_base )>::type,boost::asio::detail::awaitable_thread>::value,void>::type *)'
1> with
1> [
1> Executor=boost::asio::any_io_executor
1> ]
1> D:\dev\boost_lib\boost\asio\impl\awaitable.hpp(405,11):
1> see reference to alias template instantiation 'boost::asio::result_of_t<boost::asio::async_result<boost::asio::use_awaitable_tboost::asio::any_io_executor,agrpc::b::detail::StatusSenderImplementationBase::Signature>::initiate::<lambda_1>(boost::asio::detail::awaitable_frame_base *)>' being compiled
1> with
1> [
1> Executor=boost::asio::any_io_executor
1> ]
1> D:\dev\boost_lib\boost\asio\detail\type_traits.hpp(131,44):
1> see reference to class template instantiation 'boost::asio::result_of<boost::asio::async_result<boost::asio::use_awaitable_tboost::asio::any_io_executor,agrpc::b::detail::StatusSenderImplementationBase::Signature>::initiate::<lambda_1> (boost::asio::detail::awaitable_frame_base *)>' being compiled
1> with
1> [
1> Executor=boost::asio::any_io_executor
1> ]
1> D:\dev\boost_lib\boost\asio\detail\type_traits.hpp(128,37):
1> see reference to class template instantiation 'std::invoke_result<F,boost::asio::detail::awaitable_frame_base >' being compiled
1> with
1> [
1> F=boost::asio::async_result<boost::asio::use_awaitable_tboost::asio::any_io_executor,agrpc::b::detail::StatusSenderImplementationBase::Signature>::initiate::<lambda_1>,
1> Executor=boost::asio::any_io_executor
1> ]
1> C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.39.33519\include\type_traits(1843,38):
1> see reference to alias template instantiation 'std::_Decltype_invoke_nonzero<_Callable,boost::asio::detail::awaitable_frame_base,>' being compiled
1> with
1> [
1> _Callable=boost::asio::async_result<boost::asio::use_awaitable_tboost::asio::any_io_executor,agrpc::b::detail::StatusSenderImplementationBase::Signature>::initiate::<lambda_1>,
1> Executor=boost::asio::any_io_executor
1> ]
1> C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.39.33519\include\type_traits(1635,1):
1> see reference to function template instantiation 'boost::asio::detail::awaitable_handler<Executor,grpc::Status> *boost::asio::async_result<boost::asio::use_awaitable_t,agrpc::b::detail::StatusSenderImplementationBase::Signature>::initiate::<lambda_1>::operator ()<boost::asio::detail::awaitable_frame_base>(_T1 *) const' being compiled
1> with
1> [
1> Executor=boost::asio::any_io_executor,
1> _T1=boost::asio::detail::awaitable_frame_baseboost::asio::any_io_executor
1> ]
1> D:\dev\boost_lib\boost\asio\impl\use_awaitable.hpp(286,16):
1> see reference to function template instantiation 'boost::asio::detail::awaitable_handler<Executor,grpc::Status> *boost::asio::async_result<boost::asio::use_awaitable_t,agrpc::b::detail::StatusSenderImplementationBase::Signature>::do_init<Initiation,agrpc::b::detail::ClientUnaryRequestSenderInitiation,Implementation>(boost::asio::detail::awaitable_frame_base *,Initiation &,boost::asio::use_awaitable_t,agrpc::b::detail::ClientUnaryRequestSenderInitiation &,Implementation &)' being compiled
1> with
1> [
1> Executor=boost::asio::any_io_executor,
1> Initiation=agrpc::b::detail::SubmitSenderImplementationOperation,
1> ResponseT=Grpc::ServiceTask,
1> Implementation=agrpc::b::detail::ClientUnaryRequestSenderImplementation<std::unique_ptr<grpc::ClientAsyncResponseReaderGrpc::ServiceTask,std::default_delete<grpc::ClientAsyncResponseReaderGrpc::ServiceTask>> Grpc::TaskService::Stub::PrepareAsyncPostRequestServiceTask(grpc::ClientContext *,const Grpc::ServiceTask &,grpc::CompletionQueue *)>
1> ]
1> D:\dev\boost_lib\boost\asio\impl\use_awaitable.hpp(276,14):
1> see reference to function template instantiation 'void agrpc::b::detail::SubmitSenderImplementationOperation::operator ()<boost::asio::detail::awaitable_handler<Executor,grpc::Status>,agrpc::b::detail::ClientUnaryRequestSenderInitiation,agrpc::b::detail::ClientUnaryRequestSenderImplementation<std::unique_ptr<grpc::ClientAsyncResponseReaderGrpc::ServiceTask,std::default_delete<grpc::ClientAsyncResponseReaderGrpc::ServiceTask>> Grpc::TaskService::Stub::PrepareAsyncPostRequestServiceTask(grpc::ClientContext *,const Grpc::ServiceTask &,grpc::CompletionQueue *)>>(CompletionHandler &&,const Initiation &,Implementation &&)' being compiled
1> with
1> [
1> Executor=boost::asio::any_io_executor,
1> ResponseT=Grpc::ServiceTask,
1> CompletionHandler=boost::asio::detail::awaitable_handlerboost::asio::any_io_executor,grpc::Status,
1> Initiation=agrpc::b::detail::ClientUnaryRequestSenderInitiationGrpc::ServiceTask,
1> Implementation=agrpc::b::detail::ClientUnaryRequestSenderImplementation<std::unique_ptr<grpc::ClientAsyncResponseReaderGrpc::ServiceTask,std::default_delete<grpc::ClientAsyncResponseReaderGrpc::ServiceTask>> Grpc::TaskService::Stub::PrepareAsyncPostRequestServiceTask(grpc::ClientContext *,const Grpc::ServiceTask &,grpc::CompletionQueue *)>
1> ]
1> D:\dev\asio-grpc\include\agrpc\detail\initiate_sender_implementation.hpp(42,17):
1> see reference to function template instantiation 'void agrpc::b::detail::submit_sender_implementation_operation<CompletionHandler,Initiation,Implementation>(agrpc::b::GrpcContext &,CompletionHandler &&,const Initiation &,Implementation &&)' being compiled
1> with
1> [
1> CompletionHandler=boost::asio::detail::awaitable_handlerboost::asio::any_io_executor,grpc::Status,
1> Initiation=agrpc::b::detail::ClientUnaryRequestSenderInitiationGrpc::ServiceTask,
1> Implementation=agrpc::b::detail::ClientUnaryRequestSenderImplementation<std::unique_ptr<grpc::ClientAsyncResponseReaderGrpc::ServiceTask,std::default_delete<grpc::ClientAsyncResponseReaderGrpc::ServiceTask>> Grpc::TaskService::Stub::PrepareAsyncPostRequestServiceTask(grpc::ClientContext *,const Grpc::ServiceTask &,grpc::CompletionQueue *)>
1> ]
1> D:\dev\asio-grpc\include\agrpc\detail\sender_implementation_operation.hpp(143,13):
1> see reference to function template instantiation 'agrpc::b::detail::SenderImplementationOperation<Implementation,DecayedHandler> *agrpc::b::detail::allocate_operation<agrpc::b::detail::SenderImplementationOperationTemplate::Type,CompletionHandler,agrpc::b::GrpcContext&,const Initiation&,Implementation>(Handler &&,agrpc::b::GrpcContext &,const Initiation &,Implementation &&)' being compiled
1> with
1> [
1> Implementation=agrpc::b::detail::ClientUnaryRequestSenderImplementation<std::unique_ptr<grpc::ClientAsyncResponseReaderGrpc::ServiceTask,std::default_delete<grpc::ClientAsyncResponseReaderGrpc::ServiceTask>> Grpc::TaskService::Stub::PrepareAsyncPostRequestServiceTask(grpc::ClientContext *,const Grpc::ServiceTask &,grpc::CompletionQueue *)>,
1> CompletionHandler=boost::asio::detail::awaitable_handlerboost::asio::any_io_executor,grpc::Status,
1> Initiation=agrpc::b::detail::ClientUnaryRequestSenderInitiationGrpc::ServiceTask,
1> Handler=boost::asio::detail::awaitable_handlerboost::asio::any_io_executor,grpc::Status
1> ]
1> D:\dev\asio-grpc\include\agrpc\detail\allocate.hpp(93,70):
1> see reference to function template instantiation 'agrpc::b::detail::AllocationGuard<std::allocator_traits<_Alloc>::rebind_traits> agrpc::b::detail::allocate(const Allocator &,Args &&...)' being compiled
1> D:\dev\asio-grpc\include\agrpc\detail\allocate.hpp(90,66):
1> see reference to alias template instantiation 'agrpc::b::detail::RebindAllocatorTraits<Op,std::allocator>' being compiled
1> D:\dev\asio-grpc\include\agrpc\detail\allocate.hpp(29,83):
1> see reference to class template instantiation 'std::allocator_traits<std::allocator>' being compiled
1> C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.39.33519\include\xmemory(750,27):
1> see reference to class template instantiation 'std::_Default_allocator_traits<_Alloc>' being compiled
1> with
1> [
1> _Alloc=std::allocator
1> ]
1> C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.39.33519\include\xmemory(709,30):
1> while compiling class template member function 'void std::_Default_allocator_traits<_Alloc>::deallocate(_Alloc &,agrpc::b::detail::SenderImplementationOperation<Implementation,DecayedHandler> *const ,const std::_Default_allocator_traits<_Alloc>::size_type)'
1> with
1> [
1> _Alloc=std::allocator,
1> Implementation=agrpc::b::detail::ClientUnaryRequestSenderImplementation<std::unique_ptr<grpc::ClientAsyncResponseReaderGrpc::ServiceTask,std::default_delete<grpc::ClientAsyncResponseReaderGrpc::ServiceTask>> Grpc::TaskService::Stub::PrepareAsyncPostRequestServiceTask(grpc::ClientContext *,const Grpc::ServiceTask &,grpc::CompletionQueue *)>
1> ]
1> D:\dev\asio-grpc\include\agrpc\detail\allocate.hpp(82,27):
1> see the first reference to 'std::_Default_allocator_traits<_Alloc>::deallocate' in 'agrpc::b::detail::AllocationGuard<std::allocator_traits<std::allocator>>::destroy_deallocate_using_traits'
1> with
1> [
1> _Alloc=std::allocator
1> ]
1> D:\dev\asio-grpc\include\agrpc\detail\allocate.hpp(62,44):
1> see the first reference to 'agrpc::b::detail::AllocationGuard<std::allocator_traits<std::allocator>>::destroy_deallocate_using_traits' in 'agrpc::b::detail::AllocationGuard<std::allocator_traits<std::allocator>>::~AllocationGuard'
1> D:\dev\asio-grpc\include\agrpc\detail\allocate_operation.hpp(51,9):
1> see the first reference to 'agrpc::b::detail::AllocationGuard<std::allocator_traits<std::allocator>>::~AllocationGuard' in 'agrpc::b::detail::allocate_operation'
1> C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.39.33519\include\xmemory(718,25):
1> see reference to variable template 'const size_t _New_alignof<agrpc::b::detail::SenderImplementationOperation<agrpc::b::detail::ClientUnaryRequestSenderImplementation<&Grpc::TaskService::Stub::PrepareAsyncPostRequestServiceTask>,boost::asio::detail::awaitable_handlerboost::asio::executor,grpc::Status > >' being compiled
1> C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.39.33519\include\xmemory(82,63):
1> see reference to class template instantiation 'agrpc::b::detail::SenderImplementationOperation<Implementation,DecayedHandler>' being compiled
1> with
1> [
1> Implementation=agrpc::b::detail::ClientUnaryRequestSenderImplementation<std::unique_ptr<grpc::ClientAsyncResponseReaderGrpc::ServiceTask,std::default_delete<grpc::ClientAsyncResponseReaderGrpc::ServiceTask>> Grpc::TaskService::Stub::PrepareAsyncPostRequestServiceTask(grpc::ClientContext *,const Grpc::ServiceTask &,grpc::CompletionQueue *)>
1> ]
1> D:\dev\asio-grpc\include\agrpc\detail\sender_implementation_operation.hpp(36,56):
1> see reference to class template instantiation 'agrpc::b::detail::WorkTrackerboost::asio::executor,false' being compiled
`
The error trace is extensive, but seems related to boost::asio::awaitable and issues with work_ being used as void. A key observation is that boost::asio::any_io_executor does not support the boost::asio::execution::outstanding_work_t::tracked_t property. As a result, when using boost::asio::prefer_result<Executor, Property>::type, the evaluated type ends up being void.
Would it be possible to get some guidance on whether this is an implementation issue in Asio-GRPC or a misuse on my part? Any insights would be greatly appreciated.
Thanks for the report. This error occurs only when you define BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT
. This seems to enable some backwards compatibility, according to the documentation:
Polymorphic I/O Executor
The any_io_executor type alias is the default runtime-polymorphic executor for all I/O objects. This type alias points to the execution::any_executor<> template with a set of supportable properties specified for use with I/O.
This new name may break existing code that directly uses the old polymorphic wrapper, executor. If required for backward compatibility, ASIO_USE_TS_EXECUTOR_AS_DEFAULT can be defined, which changes the any_io_executor type alias to instead point to the executor polymorphic wrapper.
I suspect that your code or some third-party code defines this preprocessor definition. I can change the code to make it compatible. In the meantime, check where it is defined and if it is coming from an open-source library then let me know the name, I am curious how/why they are defining it.
I checked, and it is not included in any other library. It seems the issue arises because I'm using the BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT option while using other Boost libraries (tcp, v1, process, timer, etc.) in my ongoing project. If I remove the defined BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT, various errors occur in the previous code. I would greatly appreciate it if you could make this option compatible.
Fixed in https://github.com/Tradias/asio-grpc/releases/tag/v3.2.1 for now