代码之家  ›  专栏  ›  技术社区  ›  DocDriven

访问无序映射中的类实例方法导致编译错误

  •  0
  • DocDriven  · 技术社区  · 3 年前

    概述

    我正在用C++实现一个生产者-消费者模型。我有多个消费者,每个消费者都有自己的线程和队列。为了便于访问,我想要一个表单<ID、消费者实例>,这样我就可以在向consumers线程推送数据时通过查找简单地获取它。当试图访问存储实例方法时,编译器会抛出一个错误。

    密码

    使用者类启动一个带有附加FIFO队列的线程,并等待项目被推入(此处提供队列头: https://github.com/cameron314/readerwriterqueue/blob/master/readerwriterqueue.h )

    // consumer.h
    #include <functional>
    #include <thread>
    #include "readerwriterqueue.h"
    
    // TYPE HAS TO BE A POINTER
    template<typename T>
    class Consumer
    {
    public:
        Consumer(int id, std::function<void(int, T&)> func) :
            m_id(id), m_func(func) {}
    
        ~Consumer(){
            m_running = false;
            this->pushBack(nullptr);
            m_thread.join();
        }
    
        // satisfy rule of three; disallow copying as we manage a thread
        Consumer(const Consumer&) = delete;
        Consumer& operator=(const Consumer&) = delete;
    
        void pushBack(const T& t){
            m_BufferQueue.enqueue(t);
        }
    
    private:
    
        void work() {
            m_running = true;
    
            while(m_running || m_BufferQueue.peek())
            {
                T t;
                m_BufferQueue.wait_dequeue(t);
    
                if (t == nullptr)
                    break;
    
                m_func(m_id, t);
            }
        }
    
        int m_id;
        std::function<void(int, T&)> m_func;
        moodycamel::BlockingReaderWriterQueue<T> m_BufferQueue{64};
        std::thread m_thread{&Consumer::work, this};
        std::atomic_bool m_running;
    };
    

    我想创建这个类的多个实例,并将它们放在一个无序的映射中,这样我就可以在必要时推入它们的队列。据我所知,模板可以帮助我避免在创建对象并将其直接放置在映射中时编写移动构造函数/赋值运算符。

    // main_player.cpp
    #include <iostream>
    #include <unordered_map>
    #include "consumer.h"
    
    void func(int id, int* val)
    {
        std::cout << "Thread " << id << " received value " << *val << "\n";
    }
    
    int main(int argc, char** argv) {
    
        std::unordered_map<int, Consumer<int*>> consumers;
    
        consumers.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple(0, func));
    
        // push into queues here and let the threads do the work
        for(int i = 0; i < 5; i++)
            consumers[0].pushBack(&i)
    
        return 0;
    }
    

    编译器在将返回推送到队列中时出现问题。从错误日志中,我可以推断他似乎确实构建了另一个实例,但失败了。有人能帮我吗?

    错误日志

    In file included from /usr/include/c++/7/functional:54:0,
                     from ../consumer.h:4,
                     from ../main_player.cpp:31:
    /usr/include/c++/7/tuple: In instantiation of ‘std::pair<_T1, _T2>::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>) [with _Args1 = {int&&}; long unsigned int ..._Indexes1 = {0}; _Args2 = {}; long unsigned int ..._Indexes2 = {}; _T1 = const int; _T2 = Consumer<int*>]’:
    /usr/include/c++/7/tuple:1641:63:   required from ‘std::pair<_T1, _T2>::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>) [with _Args1 = {int&&}; _Args2 = {}; _T1 = const int; _T2 = Consumer<int*>]’
    /usr/include/c++/7/ext/new_allocator.h:136:4:   required from ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::pair<const int, Consumer<int*> >; _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<>}; _Tp = std::pair<const int, Consumer<int*> >]’
    /usr/include/c++/7/bits/alloc_traits.h:475:4:   required from ‘static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = std::pair<const int, Consumer<int*> >; _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<>}; _Tp = std::pair<const int, Consumer<int*> >; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<std::pair<const int, Consumer<int*> > >]’
    /usr/include/c++/7/bits/hashtable_policy.h:2066:37:   required from ‘std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_type* std::__detail::_Hashtable_alloc<_NodeAlloc>::_M_allocate_node(_Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<>}; _NodeAlloc = std::allocator<std::__detail::_Hash_node<std::pair<const int, Consumer<int*> >, false> >; std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_type = std::__detail::_Hash_node<std::pair<const int, Consumer<int*> >, false>]’
    /usr/include/c++/7/bits/hashtable_policy.h:750:8:   required from ‘std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::mapped_type& std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::operator[](std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::key_type&&) [with _Key = int; _Pair = std::pair<const int, Consumer<int*> >; _Alloc = std::allocator<std::pair<const int, Consumer<int*> > >; _Equal = std::equal_to<int>; _H1 = std::hash<int>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>; std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::mapped_type = Consumer<int*>; std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::key_type = int]’
    /usr/include/c++/7/bits/unordered_map.h:977:20:   required from ‘std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type& std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type&&) [with _Key = int; _Tp = Consumer<int*>; _Hash = std::hash<int>; _Pred = std::equal_to<int>; _Alloc = std::allocator<std::pair<const int, Consumer<int*> > >; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type = Consumer<int*>; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type = int]’
    ../main_player.cpp:48:20:   required from here
    /usr/include/c++/7/tuple:1652:70: error: no matching function for call to ‘Consumer<int*>::Consumer()’
             second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
                                                                          ^
    In file included from ../main_player.cpp:31:0:
    ../consumer.h:13:5: note: candidate: Consumer<T>::Consumer(int, std::function<void(int, T&)>) [with T = int*]
         Consumer(int id, std::function<void(int, T&)> func) :
         ^~~~~~~~
    ../consumer.h:13:5: note:   candidate expects 2 arguments, 0 provided
    make: *** [main_player.o] Error 1
    subdir.mk:66: recipe for target 'main_player.o' failed
    "make -j20 all" terminated with exit code 2. Build might be incomplete.
    
    18:01:03 Build Failed. 3 errors, 0 warnings. (took 739ms)
    
    1 回复  |  直到 3 年前
        1
  •  1
  •   user12002570    3 年前

    您需要添加 默认构造函数 在课堂上 Consumer 正如错误所说

    error: no matching function for call to ‘Consumer<int*>::Consumer()’
    

    您可以通过以下两种方式进行操作:

    方法1

    // consumer.h
    #include <functional>
    #include <thread>
    #include "readerwriterqueue.h"
    
    // TYPE HAS TO BE A POINTER
    template<typename T>
    class Consumer
    {
    public:
        Consumer(int id, std::function<void(int, T&)> func) :
            m_id(id), m_func(func) {}
    
        //other member here
        
        //ADD THE DEFAULT CONSTRUCTOR 
        Consumer() = default;
        
    
    private:
    
        //...
    
        int m_id = 0; //USE IN-CLASS INITIALIZER for built in type
        //other members here
    };
    

    方法2

    // consumer.h
    #include <functional>
    #include <thread>
    #include "readerwriterqueue.h"
    
    // TYPE HAS TO BE A POINTER
    template<typename T>
    class Consumer
    {
    public:
        Consumer(int id, std::function<void(int, T&)> func) :
            m_id(id), m_func(func) {}
    
        //other member here
        
        //ADD THE DEFAULT CONSTRUCTOR 
        Consumer(): m_id(0)
        {
        }
        
    
    private:
    
        //...
    
        int m_id;
        //other members here
    };