当前位置: 动力学知识库 > 问答 > 编程问答 >

templates - C++ Reactor using base & derived classes containing functional objects of different types

问题描述:

I've created this example reactor program to test functionality I wanted to demonstrate.

Essentially the program defines:

  1. Two functional objects to be called on different events.

  2. A base & derived class; the intention of which is to allow different template instantiations of the derived class to be stored as in the same stl container.

  3. A reactor function which uses random numbers to simulate events, then search a container for the matching key and call the functional-object to do its work.

  4. Main does some setup work then calls the reactor function to run in a different thread.

EDIT: Have modified the code so that it now compiles & runs. Apologies, code is now quite long; it started out as a minimal test program. Have added extra sections & lots of print statements to elucidate the functionality. It remains here in case it's of interest to others.

#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;

}

网友答案:

When I try to compile this (g++ --std=c++11 reactor.cpp -pthread) I get a somewhat cryptic

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

This appears to be the result of trying to pass stack references to the thread constructor. These are values that are going, by definition, to be copied into the thread object and then passed to the reactor() function. You need to allow these objects to be copied, or dynamically allocate object and pass pointers.

From http://en.cppreference.com/w/cpp/thread/thread/thread:

The arguments to the thread function are copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g. with std::ref or std::cref).

Keep in mind if you use std::ref, you are still passing this data to another thread, so that will only work if you know that the object you are passing to the other thread will remain alive through the lifetime of the new thread.

If I take out the references in the reactor parameters this compiles fine for me (with a linker error for one of your callFunctionalObject functions not being defined).

分享给朋友:
您可能感兴趣的文章:
随机阅读: