C ++ Reactor使用base&包含不同类型的功能对象的派生类

时间:2014-11-18 16:19:17

标签: c++ templates functor generic-programming reactor

我已经创建了这个示例反应器程序来测试我想要演示的功能。

基本上该程序定义:

  1. 要在不同事件上调用的两个功能对象。

  2. 基地&派生类;其目的是允许派生类的不同模板实例存储在同一个stl容器中。

  3. 使用随机数模拟事件的反应堆函数,然后在容器中搜索匹配的键并调用功能对象来完成其工作。

  4. Main执行一些设置工作,然后调用reactor函数在另一个线程中运行。

  5. 编辑:修改了代码,以便现在编译和编译运行。道歉,代码现在很长;它最初是一个最小的测试程序。增加了额外的部分和大量的印刷语句来阐明功能。它保留在这里以防其他人感兴趣。

    #include <functional>
    #include <iostream>
    #include <stdlib.h>
    #include <chrono>
    #include <thread>
    #include <unordered_map>
    #include <utility>
    #include <memory>
    
    class Pollin_Functional_Object
    {
    public:
        //Constructor
        Pollin_Functional_Object(const int cnt) : count(cnt)
        {
            std::cout << "Pollin_Functional_Object: Constructor" << std::endl;
        }
    
        //Copy Constructor
        Pollin_Functional_Object(const Pollin_Functional_Object &orig) : count(orig.count)
        {
            std::cout << "Pollin_Functional_Object: Copy Constructor" << std::endl;
        }
    
        //Copy assignment
        Pollin_Functional_Object& operator= (const Pollin_Functional_Object &that)
        {
            std::cout << "Pollin_Functional_Object: Copy Assignment Constructor" << std::endl;      
            if (this != &that)
            {           
                count = that.count;
            }
            return *this;
        }
    
        //Move constructor
        Pollin_Functional_Object(Pollin_Functional_Object &&orig) /*noexcept NOT VS2013*/ : count(orig.count)
        {
            std::cout << "Pollin_Functional_Object: Move Constructor" << std::endl;     
        }
    
        //Move Assignment
        Pollin_Functional_Object& operator=(Pollin_Functional_Object &&that) /*noexcept NOT VS2013*/
        {
            std::cout << "Pollin_Functional_Object: Move Assignment Constructor" << std::endl;
            if (this != &that)
            {
                count = that.count;         
            }
            return *this;
        }
    
        //Operators
        bool operator==(const Pollin_Functional_Object &anotherPollin_Functional_Object) const
        {
            return (count == anotherPollin_Functional_Object.count);
        }
    
        void operator()(const int &in) //const
        {
            std::cout << "Pollin__Functional_Object: operator(" << in << ") Count: " << ++count << std::endl;       
        }
    
        ~Pollin_Functional_Object()
        {
            std::cout << "Pollin_Functional_Object: Destructor Called." << std::endl;
        }
    
    private:
        int count;
    };
    
    
    class Pollout_Functional_Object
    {
    public:
        //Constructor
        Pollout_Functional_Object(const int count) : count(count)
        {
            std::cout << "Pollout_Functional_Object: Constructor" << std::endl;
        }
    
        //Copy Constructor
        Pollout_Functional_Object(const Pollout_Functional_Object &orig) : count(orig.count)
        {
            std::cout << "Pollout_Functional_Object: Copy Constructor" << std::endl;
        }
    
        //Copy assignment
        Pollout_Functional_Object& operator= (const Pollout_Functional_Object &that)
        {
            std::cout << "Pollout_Functional_Object: Copy Assignment Constructor" << std::endl;
            if (this != &that)
            {
                count = that.count;
            }
            return *this;
        }
    
        //Move constructor
        Pollout_Functional_Object(Pollout_Functional_Object &&orig) /*noexcept NOT VS2013*/ : count(orig.count)
        {
            std::cout << "Pollout_Functional_Object: Move Constructor" << std::endl;
        }
    
        //Move Assignment
        Pollout_Functional_Object& operator=(Pollout_Functional_Object &&that) /*noexcept NOT VS2013*/
        {
            std::cout << "Pollout_Functional_Object: Move Assignment Constructor" << std::endl;
            if (this != &that)
            {
                count = that.count;
            }
            return *this;
        }
    
        //Operators
        bool operator==(const Pollout_Functional_Object &anotherPollout_Functional_Object) const
        {
            return (count == anotherPollout_Functional_Object.count);
        }
    
        void operator()(const int &in) //const
        {
            std::cout << "Pollout_Functional_Object: operator(" << in << ") Count: " << ++count << std::endl;
        }
    
        ~Pollout_Functional_Object()
        {
            std::cout << "Pollout_Functional_Object: Destructor Called." << std::endl;
        }
    
    private:
        int count;
    };
    
    //Needs to be non-templated base class.
    class Instruction_Base
    {
    public:
        //Default Constructor
        Instruction_Base() = default;
    
        //Constructor
        Instruction_Base(const std::string &nme):name(nme)
        {
            std::cout << "Instruction_Base: Constructor" << std::endl;
        }
    
        //Copy Constructor
        Instruction_Base(const Instruction_Base &orig) : name(orig.name)
        {
            std::cout << "Instruction_Base: Copy Constructor" << std::endl;
        }
    
        //Copy assignment
        Instruction_Base& operator= (const Instruction_Base &that)
        {
            std::cout << "Instruction_Base: Copy Assignment Constructor" << std::endl;
            if (this != &that)
            {
                name = that.name;
            }
            return *this;
        }
    
        //Move constructor
        Instruction_Base(Instruction_Base &&orig) /*noexcept NOT VS2013*/ : name(orig.name)
        {
            std::cout << "Instruction_Base: Move Constructor" << std::endl;
        }
    
        //Move Assignment
        Instruction_Base& operator=(Instruction_Base &&that) /*noexcept NOT VS2013*/
        {
            std::cout << "Instruction_Base: Move Assignment Constructor" << std::endl;
            if (this != &that)
            {
                name = that.name;
            }
            return *this;
        }
    
        virtual ~Instruction_Base()// = default;//dynamic binding. Virtual destructor is necessary in base class even if it does no work.
        {
            std::cout << "Instruction_Base: Destructor Called" << std::endl;
        }
    
        //Operator
        bool operator==(const Instruction_Base &anotherInstruction_Base) const
        {
            return (name == anotherInstruction_Base.name);
        }
    
        virtual void callFunctionalObject(const int &in)//marked virtual.  Is overridden in derived class Instruction.
        {
            std::cout << "Instruction_Base: callFunctionalObject(" << in << ")" << std::endl;
        }
    
    private:
        std::string name;
    };
    
    //Derived class; templated.  Will store functional-objects of different specified types.
    template<typename Functional_Object>
    class Instruction : public Instruction_Base //inherits from
    {
    public:
        //Default Constructor
        Instruction() = default;
    
        //Constructor
        Instruction(const std::string &nme, const std::shared_ptr<Functional_Object> &funcObj) : fo(funcObj)
        {
            std::cout << "Instruction: Constructor" << std::endl;
        }
    
        //Copy Constructor
        Instruction(const Instruction &orig) : Instruction_Base(orig), fo(orig.fo)
        {
            std::cout << "Instruction: Copy Constructor" << std::endl;
        }
    
        //Copy assignment
        Instruction& operator= (const Instruction &that)
        {
            std::cout << "Instruction: Copy Assignment Constructor" << std::endl;
            Instruction_Base::operator=(that);
            if (this != &that)
            {
                fo = that.fo;
            }
            return *this;
        }
    
        //Move constructor
        Instruction(Instruction &&orig) /*noexcept NOT VS2013*/ : Instruction_Base(std::move(orig)), fo(orig.fo)
        {
            std::cout << "Instruction: Move Constructor" << std::endl;
        }
    
        //Move Assignment
        Instruction& operator=(Instruction &&that) /*noexcept NOT VS2013*/
        {
            std::cout << "Instruction: Move Assignment Constructor" << std::endl;
            Instruction_Base::operator=(that);
            if (this != &that)
            {
                fo = that.fo;
            }
            return *this;
        }
    
        //Destructor
        ~Instruction()
        {
            std::cout << "Instruction: Destructor Called" << std::endl;
        }
    
        //Operators
        bool operator==(const Instruction_Base &anotherInstruction) const
        {
            return (name == anotherInstruction.name &&
                fo == anotherInstruction.fo);
        }
    
        void callFunctionalObject(const int &in) override
        {
            //std::cout << "Instruction: callFunctionalObject(" << in << ")" << std::endl;
            (*fo)(in);
        }
    
    private:
        std::shared_ptr<Functional_Object> fo;
    };
    
    class InstructionsStore
    {
    public: InstructionsStore()
            {
            std::cout << "InstructionsStore: Constructor" << std::endl;
            }
    
            //Copy Constructor
            InstructionsStore(const InstructionsStore &orig) : instructions(orig.instructions)
            {
                std::cout << "InstructionsStore: Copy Constructor" << std::endl;
            }
    
            //Copy assignment
            InstructionsStore& operator= (const InstructionsStore &that)
            {
                std::cout << "InstructionsStore: Copy Assignment Constructor" << std::endl;
                if (this != &that)
                {
                    instructions = that.instructions;               
                }
                return *this;
            }
    
            //Move constructor
            InstructionsStore(InstructionsStore &&orig) /*noexcept NOT VS2013*/ : instructions(orig.instructions)
            {
                std::cout << "InstructionsStore: Move Constructor" << std::endl;
            }
    
            //Move Assignment
            InstructionsStore& operator=(InstructionsStore &&that) /*noexcept NOT VS2013*/
            {
                std::cout << "InstructionsStore: Move Assignment Constructor" << std::endl;
                if (this != &that)
                {
                    instructions = that.instructions;               
                }
                return *this;
            }
    
            //Operators
            bool operator==(const InstructionsStore &anotherInstructionsStore) const
            {
                return (instructions == anotherInstructionsStore.instructions);
            }
    
    //Setter
        void addInstruction(const std::string nme, const std::shared_ptr<Instruction_Base> &ib)
        {
                instructions.insert(std::pair<std::string, std::shared_ptr<Instruction_Base>>(nme, ib));
        }
    
    //Getter
        std::shared_ptr<Instruction_Base> getInstruction(const std::string nme)//returns pointer to derived Instruction type object
        {
            auto got = instructions.find(nme);
            if (got != instructions.end())
            {
                //std::cout << "InstructionsStore: getInstruction(" << (got->first).c_str() << ")" << std::endl;
                return got->second;
            }       
        }
    
    private:
        //Specifying std::shared_ptr<Instruction_Base> base class also allows storage of pointers to types derived
        //from Instruction_Base i.e. templated Instruction class objects storing functional-objects of different types.
        //Pointers only though, does not work with actual objects.
        std::unordered_map<std::string, std::shared_ptr<Instruction_Base>> instructions;
    };
    
    //Reactor Function
    void reactor(const int &iterations, const std::shared_ptr<InstructionsStore> &is)
    {
    //Prepare variables
    int runLoop(0);
    int number(0);
    std::string searchFor("");
    srand(time(NULL));
    
    while (runLoop < iterations)
     {
      number = rand() % 100 + 1;//in the range 1 to 100
    
      if (number >= 50)
      {
          searchFor = "pollin";
      }
      else
      { 
          searchFor = "pollout";
      }
    
      //Find the relevant object
      std::shared_ptr<Instruction_Base> ib = is->getInstruction(searchFor);
    
      //Call the functional-object; passes the call via
      //the virtual function & dynamic binding in the base class Instruction_Base to
      //the overridden derived Instruction class member function.
      ib->callFunctionalObject(number);
    
      std::this_thread::sleep_for(std::chrono::milliseconds(1000));
      ++runLoop;
     }
    }
    
    
    int main(int argc, char* argv[])
    {
        //Instantiate the functional-objects and corresponding shared pointers.
        std::shared_ptr <Pollin_Functional_Object> spPifo (new Pollin_Functional_Object(0));
        std::shared_ptr <Pollout_Functional_Object> spPofo(new Pollout_Functional_Object(0));
    
        //Instantiate the Instruction objects and corresponding shared pointers.
        std::shared_ptr <Instruction<Pollin_Functional_Object>> spPiInstr (new Instruction<Pollin_Functional_Object>("pollin", spPifo));
        std::shared_ptr <Instruction<Pollout_Functional_Object>> spPoInstr (new Instruction<Pollout_Functional_Object>("pollout", spPofo));
    
        //Instantiate the InstructionsStore object and corresponding shared pointer.
        std::shared_ptr<InstructionsStore> spIs(new InstructionsStore);
        spIs->addInstruction("pollin", spPiInstr);//add the instruction to the store
        spIs->addInstruction("pollout", spPoInstr);//add the instruction to the store
    
        //Then pass the InstructionsStore shared pointer to the reactor function and run.
        std::thread t1(reactor, 10, std::cref(spIs));
        t1.join();//wait for it.....    
        return 0;
    }
    

1 个答案:

答案 0 :(得分:0)

当我尝试编译它时(g ++ --std = c ++ 11 reactor.cpp -pthread)我有点神秘

/usr/include/c++/4.9/functional:1665:61: error: no type named ‘type’ in ‘class std::result_of<void (*(int, InstructionsStore))(const int&, InstructionsStore&)>’

这似乎是尝试将堆栈引用传递给线程构造函数的结果。根据定义,这些值将被复制到线程对象中,然后传递给reactor()函数。您需要允许复制这些对象,或动态分配对象并传递指针。

来自http://en.cppreference.com/w/cpp/thread/thread/thread

  

线程函数的参数按值复制。如果一个   引用参数需要传递给线程函数,它具有   被包装(例如用std :: ref或std :: cref)。

请记住,如果你使用std :: ref,你仍然会将这些数据传递给另一个线程,这样只有当你知道传递给另一个线程的对象在整个生命周期中仍然存活时才能工作。新线程。

如果我取出reactor参数中的引用,这对我编译很好(对于一个未定义的callFunctionalObject函数,链接器错误)。