Я создал этот пример реакторной программы для тестирования функциональности, которую я хотел продемонстрировать.
По сути, программа определяет:
Два функциональных объекта для вызова на разных событиях.
База & производный класс; намерение которого состоит в том, чтобы позволить различным экземплярам шаблона производного класса быть сохраненными как в том же контейнере stl.
Функция реактора, которая использует случайные числа для имитации событий, затем ищет в контейнере соответствующий ключ и вызывает функциональный объект для выполнения своей работы.
Main выполняет некоторые настройки, а затем вызывает функцию реактора для запуска в другом потоке.
РЕДАКТИРОВАТЬ: изменили код, чтобы он теперь компилируется & пробеги. Извините, код теперь довольно длинный; это началось как минимальная тестовая программа. Добавили дополнительные разделы & много печатных заявлений для выяснения функциональности. Это остается здесь в случае, если это представляет интерес для других.
#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;
}
Когда я пытаюсь скомпилировать это (g ++ —std = c ++ 11 processor.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&)>’
Похоже, это результат попытки передать стековые ссылки в конструктор потока. Это значения, которые по определению будут скопированы в объект потока и затем переданы в функцию реактора (). Вам необходимо разрешить копирование этих объектов или динамическое выделение объектов и указателей передачи.
От http://en.cppreference.com/w/cpp/thread/thread/thread:
Аргументы функции потока копируются по значению. Если
ссылочный аргумент должен быть передан в функцию потока, он имеет
быть обернутым (например, с помощью std :: ref или std :: cref).
Имейте в виду, что если вы используете std :: ref, вы по-прежнему передаете эти данные другому потоку, так что это будет работать только в том случае, если вы знаете, что объект, который вы передаете другому потоку, останется живым в течение всего времени жизни нового потока.
Если я уберу ссылки в параметрах реактора, это прекрасно скомпилируется (ошибка компоновщика для одной из ваших функций callFunctionalObject не определена).