#include <functional>
#include <iostream>
#include <thread>

using namespace std::chrono_literals;

using TypeCallbackRun = std::function<void (int)>;
using TypeCallbackBreak = std::function<bool (int)>;
using TypeCallbackFinish = std::function<void ()>;

// ───────────────────────────────────────────────────────────────────────────────────

class Producer {
		TypeCallbackRun CallbackRun;
		TypeCallbackBreak CallbackBreak;
		TypeCallbackFinish CallbackFinish;
	public:
		Producer() {}
		void Run() {
			std::cout << "Run started (10 times) ...\n";
			for (int i = 0; i < 10; ++i) {
				if (CallbackBreak && CallbackBreak(i)) break;
				if (CallbackRun) CallbackRun(i);
				std::this_thread::sleep_for(100ms);
			}
			if (CallbackFinish) CallbackFinish();
			std::cout << "\nRun finished\n";
		}
		void SetCallbacks(TypeCallbackRun r, TypeCallbackBreak b, TypeCallbackFinish f) {
			CallbackRun = r;
			CallbackBreak = b;
			CallbackFinish = f;
		}
};

// ───────────────────────────────────────────────────────────────────────────────────

class Consumer {
	public:
		bool Ready = false;
		void ProcCallbackRun(const int i) {
			std::cout << i << " ";
		}
		bool ProcCallbackBreak(const int i) {
			return i > 4;
		}
		void ProcCallbackFinish() {
			Ready = true;
		}
};

// ───────────────────────────────────────────────────────────────────────────────────

int main() {
	Producer Prod;
	Consumer Cons;
	//  так
	//
	Prod.SetCallbacks(
		std::bind(&Consumer::ProcCallbackRun, &Cons, std::placeholders::_1),
		std::bind(&Consumer::ProcCallbackBreak, &Cons, std::placeholders::_1),
		std::bind(&Consumer::ProcCallbackFinish, &Cons)
	);
	//
	//  ну или так
	//
	//	Prod.SetCallbacks(
	//	[&](int i) {
	//		Cons.ProcCallbackRun(i);
	//	},
	//	[&](int i) {
	//		return Cons.ProcCallbackBreak(i);
	//	},
	//	[&]() {
	//		Cons.ProcCallbackFinish();
	//	});
	Prod.Run();
	return 0;
}
