Hello Nathan,
Am Montag, 15. Oktober 2018 17:54:48 UTC+2 schrieb Nathan Prat:
>
> How can you use CRTP? I tried it this way, but after `cq_->Next` you can't
> static_cast to a templated class. Or am I missing something?
>
I have a mixture now of virtual inheritance and CRTP.
Basically, one super simple call root class:
// First a macro I use later
#define GRPC_NATIVE_NAME_REQUEST( name ) \
void native_name_request() { \
m_service->Request ## name ## (&m_ctx, &m_request, &m_responder, m_cq,
m_cq, this); \
}
class RpcCallBase {
public:
RpcCallBase() {};
virtual ~RpcCallBase() {};
virtual void proceed() noexcept {
MOOSE_ASSERT_MSG(true, "RPC implementation does not overload
proceed()");
};
};
This is what I use to cast the void ptr to in order to get it to RTTI the
right type. Then, on top of this, the actual CRTP base. Like this:
// First a macro I use later
#define GRPC_NATIVE_NAME_REQUEST( name ) \
void native_name_request() { \
m_service->Request ## name ## (&m_ctx, &m_request, &m_responder, m_cq,
m_cq, this); \
}
template< class DerivedType, class RequestType, class ResponseType >
class MyServiceCall : public RpcCallBase {
public:
typedef MyServiceCall<DerivedType, RequestType, ResponseType>
base_type;
MyServiceCall() {
// constructor with service specific stuff such as parent
object and so on
proceed(); like in the example
}
void proceed() noexcept override {
// Much like the example, except:
if (m_status == CREATE) {
m_status = PROCESS;
static_cast<DerivedType *>(this)->native_name_request();
// this is what the macro injects in order to fake the right
type in here. See below.
} else if (m_status == PROCESS) {
// new object of CRTP derived type
new base_type(m_service, m_cq, m_parent);
// CRTP to the actual work, overloaded by derived class
grpc::Status retstat = static_cast<DerivedType
*>(this)->work();
}
// rest of the stuff pretty much like the example except template types
}
and then, each call can be implemented nicely:
class FooMethodCall : public MyServiceCall<FooMethodCall, FooMethodRequest,
FooMethodResponse> {
public:
GRPC_NATIVE_NAME_REQUEST( FooMethod ) // I know, not perfect but
it does the trick
FooMethodCall(MyService::AsyncService *n_service,
ServerCompletionQueue *n_cq, MyServiceImpl *n_parent)
: base_type(n_service, n_cq, n_parent) {
}
grpc::Status work() {
// do the actual work and return a status object
}
}
Finally, in the async loop it looks like this:
void MyServiceImpl::HandleRpcs() {
// Spawn a new CallData instance to serve new clients.
// The q takes ownership
new FooMethodCall(&m_service_instance, m_cq.get(), this);
new BarMethodCall(&m_service_instance, m_cq.get(), this);
void* tag; // uniquely identifies a request.
bool ok;
while (true) {
if (!m_cq->Next(&tag, &ok)) {
BOOST_LOG_SEV(logger(), normal) << "service shutting down";
break;
}
RpcCallBase *call = static_cast<RpcCallBase *>(tag);
if (!ok) {
// This seems to be the case while the q is draining of
events
// during shutdown I'm gonna delete them
delete call;
continue;
}
// hand over to the call object to do the rest
call->proceed();
}
}
And it works. This way I don't need any further type guessing or casting
beyond the RpcCallBase
HTH,
Stephan
--
You received this message because you are subscribed to the Google Groups
"grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/grpc-io.
To view this discussion on the web visit
https://groups.google.com/d/msgid/grpc-io/922f4158-87db-4d2e-a0eb-3266aee45137%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.