简体   繁体   中英

grpc & protobuf — error: no type named 'type' in std::result_of<>

In my program I have a Master class (grpc async client) which distributes work to all the Workers (grpc async servers), and it does this via a class called WorkerClient which handles all communication overhead.

My Master class tries to setup a (detached) background thread to wait for the response from the server, and this is where my difficulty arises.

One strategy I've tried was to make my "AsyncComplete" function part of the WorkerClient class (identical to an approach for a recent program involving async client-server grpc based on the Async-Greeter tutorial on grpc.io), the class details for this approach are below.

    class WorkerClient {
        public:
        WorkerClient(std::shared_ptr<grpc::Channel> channel);

        void MapReduceWork(masterworker::WorkReq);
        void AsyncComplete(void *, void *, int);

        struct AsyncClientCall {
            masterworker::WorkReply     reply;
            grpc::ClientContext         context;
            grpc::Status                status;
std::unique_ptr<grpc::ClientAsyncResponseReader<masterworker::WorkReply>> rsp_reader;
        };

        std::mutex                                          mtx;
        std::unique_ptr<masterworker::MasterWorker::Stub>   stub;
        grpc::CompletionQueue                               cq;
        masterworker::WorkReq                               work_req;
        ClientState                                         state;
    };

    class Master {
            public:
            Master(const MapReduceSpec&, const std::vector<FileShard>&);
            ......   
            private:
            std::mutex                      mtx;
            std::vector<FileShard>          map_tasks;
            std::vector<ReduceTask *>       reduce_tasks;
            std::vector<WorkerClient *>     clients;
            std::vector<std::string>        m_interm_files;

            std::vector<FileShard>          shards;
            MapReduceSpec                   mr_config;
        };

Here are the relevant function details

void WorkerClient::AsyncComplete(void *c, void *m, int client_num)
{
    void            *got_tag = NULL;
    bool            ok = false;
    Master          *mast = static_cast<Master*>(m);
    WorkerClient    *client = static_cast<WorkerClient*>(c);

    cq.Next(&got_tag, &ok);
    if (ok == false) {
        fprintf(stderr, "cq->Next false!\n");
        return;
    }
    ......
}

The call to create the thread

void Master::RunMapJob()
{
        // clients[] is of type WorkerClient        
        ptr = new std::thread(&WorkerClient::AsyncComplete,
                static_cast<void*>(clients[i]), static_cast<void*>(this), i);
        ptr->detach();
    ......
}

And finally, the problem itself

g++ -c master.cc -I../external/include -std=c++11 -g
In file included from /usr/include/c++/4.8/mutex:42:0,
                 from master.h:3,
                 from master.cc:2:
/usr/include/c++/4.8/functional: In instantiation of ‘struct std::_Bind_simple<std::_Mem_fn<void (WorkerClient::*)(void*, void*, int)>(void*, void*, int)>’:
/usr/include/c++/4.8/thread:137:47:   required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (WorkerClient::*)(void*, void*, int); _Args = {void*, void*, int&}]’
master.cc:223:65:   required from here
/usr/include/c++/4.8/functional:1697:61: error: no type named ‘type’ in ‘class std::result_of<std::_Mem_fn<void (WorkerClient::*)(void*, void*, int)>(void*, void*, int)>’
       typedef typename result_of<_Callable(_Args...)>::type result_type;
                                                             ^
/usr/include/c++/4.8/functional:1727:9: error: no type named ‘type’ in ‘class std::result_of<std::_Mem_fn<void (WorkerClient::*)(void*, void*, int)>(void*, void*, int)>’
         _M_invoke(_Index_tuple<_Indices...>)
         ^
make: *** [master.o] Error 1

So far, I have ruled out the obvious things, like not using std::ref to pass variable references to the thread function, and just in general not passing the correct thread function arguments. I have also tried to make AsyncComplete a static stand-alone function, and that didn't work either because the call to cq.Next (changed to WorkerClient->cq.Next()) was throwing a std::bad_alloc exception (not able to figure that one out either as the CompletionQueue code is behind the scenes).

If it helps, I was able to find the /usr/include/c++/4.8/functional line that seems to be choking during compile (below)

typedef typename result_of<_Callable(_Args...)>::type result_type;

Can anyone help me explain both why this is failing to compile, and what a proper fix might look like? I'm new to posting questions on here so feedback is welcome, and I know this is long, but I wanted to make sure I had all the information.

Thanks in advance.

[System details: ubuntu 14.04, protobufs 3.0, grpc built from source for protobufs 3.0]

This line is the problem:

ptr = new std::thread(&WorkerClient::AsyncComplete, static_cast<void*>(clients[i]), static_cast<void*>(this), i)

The constructor of std::thread takes a functor and arguments to it. You are supplying &WorkerClient::AsyncComplete without giving an instance of WorkerClient to it. I guess that a client is actually contained in clients[i] . If you try

ptr = new std::thread(std::bind(&WorkerClient::AsyncComplete, clients[i], static_cast<void*>(clients[i]), static_cast<void*>(this), i))

it should compile.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM