C++实现简化 QtBase(4):增加简单实用的事件机制

前面的文章已经实现了许多QObject的功能了:
C++实现一个简单的Qt信号槽机制
C++实现简化版Qt信号槽机制(2):增加内存安全保障
C++实现简化版Qt的QObject(3):增加父子关系、属性系统

但是,Qt中还有一个关键的功能是事件系统。

为了让我们的QObject也支持事件系统,我们可以设计一套简单实用的事件机制。

设计事件循环

事件系统离不开事件循环,截止到C++ 20标准库里没有一套官方的事件循环机制,可能是因为实现一个事件循环也不是什么难事吧。

为了简化我们的事件循环机制,我们用到了一个c++11引入的独特的容器:priority_queue 。它提供了一个严格的弱序列,其中每个元素都有一个优先级。在 priority_queue 中,元素被按优先级排序,最高优先级的元素总是位于队列的前端。我们将事件循环的时间按执行时间点的远近作为优先级,可以很好地简化排序逻辑。

结合boost::asio和qt的EventLoop的使用经验,我计划这个简单实用的事件循环使用的姿势如下:

refl::CEventLoop loop;
loop.post([]() {
	std::cout << "Immediate task\n";
	});//马上执行

loop.post([]() {
	std::cout << "Delayed task\n";
	}, std::chrono::seconds(1));//延时一秒

std::thread loop_thread([&loop]() {
	loop.run();
	});

std::this_thread::sleep_for(std::chrono::seconds(2));
loop.stop();//停止消息循环
loop_thread.join();

实现事件循环

在确定使用方法之后,总体的接口和功能实现就比较简单了。
核心成员变量和函数功能注释如下:

class CEventLoop {
	std::priority_queue<TimedHandler> tasks_;//成员变量:任务队列
	std::mutex mutex_;//用于等待相关
	std::condition_variable cond_;//用于等待相关
	std::atomic<bool> running_{ true };//标识是否正在运行
	
	// "post" 函数用于提交一个待执行的任务到事件循环中。
	// 参数 "handler" 是一个函数对象,代表需要异步执行的任务。
	// 参数 "delay" 表示任务延迟执行的时间,默认是立即执行(Duration::zero())。
	void post(Handler handler, Duration delay = Duration::zero()) {
	    // 对互斥量上锁,保证线程安全。
	    std::unique_lock<std::mutex> lock(mutex_);
	    // 将任务和它应该被执行的时间点(现在 + 延迟)一起存入优先级队列中。
	    tasks_.push({Clock::now() + delay, std::move(handler)});
	    // 通知一个等待中的线程(如果有的话),有新的任务已经被提交。
	    cond_.notify_one();
	}
	
	// "run" 函数启动事件循环,循环内部不断地执行任务。
	void run() {
	    // 只要 "running_" 标志为 true,事件循环就会继续运行。
	    while (running_) {
	        // 对互斥量上锁,保证线程安全。
	        std::unique_lock<std::mutex> lock(mutex_);
	        // 如果当前没有任务可执行,就等待直到有新任务被提交或者事件循环被停止。
	        if (tasks_.empty()) {
	            cond_.wait(lock, [this] { return !tasks_.empty() || !running_; });
	        }
	
	        // 当有任务可以执行时(优先级队列中最早的任务时间 <= 当前时间),执行它们。
	        while (!tasks_.empty() && tasks_.top().first <= Clock::now()) {
	            // 从队列中取出任务。
	            auto task = std::move(tasks_.top());
	            // 将任务从队列中移除。
	            tasks_.pop();
	            // 释放互斥量锁,以便其他线程可以提交任务或者修改任务队列。
	            lock.unlock();
	            // 执行任务。
	            task.second();
	            // 任务执行完毕后,再次上锁互斥量。
	            lock.lock();
	        }
	
	        // 如果队列中还有任务,等待直到队列中最早的任务到达执行时间。
	        if (!tasks_.empty()) {
	            // 等待直到最早任务的执行时间,或者条件变量被通知。
	            cond_.wait_until(lock, tasks_.top().first);
	        }
	    }
	}
};

虽然几十行代码实现的时间循环非常精简,但是也不能少了扩展能力,通过扩展可以实现更复杂的主消息循环等复杂场景。于是我们引入一个回调类IEventLoopHost:

		class IEventLoopHost {
		public:
			virtual void onWaitForTask(std::condition_variable& cond, std::unique_lock<std::mutex>& locker) = 0;
			virtual void onEvent(TimedHandler& event) = 0;
			virtual void onWaitForRun(std::condition_variable& cond, std::unique_lock<std::mutex>& locker, const TimePoint& timePoint) = 0;
		};

在特定时机可以通过回调类替换掉默认实现,从而实现完整的功能扩展。

事件循环的完整代码

后续放到github上迭代(https://github.com/kevinyangli/simple_qt_qobject.git)

class CEventLoop {
public:
	using Clock = std::chrono::steady_clock;
	using TimePoint = Clock::time_point;
	using Duration = Clock::duration;
	using Handler = std::function<void()>;
	struct TimedHandler {
		TimePoint time;
		Handler handler;
		bool operator<(const TimedHandler& other) const {
			return time > other.time;
		}
	};
	class IEventLoopHost {
	public:
		virtual void onWaitForTask(std::condition_variable& cond, std::unique_lock<std::mutex>& locker) = 0;
		virtual void onEvent(TimedHandler& event) = 0;
		virtual void onWaitForRun(std::condition_variable& cond, std::unique_lock<std::mutex>& locker, const TimePoint& timePoint) = 0;
	};
private:
	IEventLoopHost* host = nullptr;
	std::priority_queue<TimedHandler> tasks_;
	std::mutex mutex_;
	std::condition_variable cond_;
	std::atomic<bool> running_{ true };

public:
	void setHost(IEventLoopHost* host) {
		this->host = host;
	}
	void post(Handler handler, Duration delay = Duration::zero()) {
		std::unique_lock<std::mutex> lock(mutex_);
		tasks_.push({ Clock::now() + delay, std::move(handler) });
		cond_.notify_one();
	}

	void run() {
		while (running_) {
			std::unique_lock<std::mutex> lock(mutex_);
			if (tasks_.empty()) {
				if (host) {
					host->onWaitForTask(cond_, lock);
				}
				else {
					cond_.wait(lock, [this] { return !tasks_.empty() || !running_; });
				}
			}

			while (!tasks_.empty() && tasks_.top().time <= Clock::now()) {
				auto task = tasks_.top();
				tasks_.pop();
				lock.unlock();
				if (host) {
					host->onEvent(task);
				}
				else {
					task.handler();
				}

				lock.lock();
			}

			if (!tasks_.empty()) {
				if (host) {
					host->onWaitForRun(cond_, lock, tasks_.top().time);
				}
				else {
					cond_.wait_until(lock, tasks_.top().time);
				}
			}
		}
	}

	void stop() {
		running_ = false;
		cond_.notify_all();
	}

};

带上完整的测试代码,以及之前的功能实现:

#include <iostream>
#include <tuple>
#include <stdexcept>
#include <assert.h>
#include <string_view>
#include <optional>
#include <utility> // For std::forward
#include <unordered_map>
#include <functional>
#include <memory>
#include <any>
#include <type_traits> // For std::is_invocable
#include <map>

#include <chrono>
#include <thread>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <atomic>

namespace refl {

	// 这个宏用于创建字段信息
#define REFLECTABLE_PROPERTIES(TypeName, ...)  using CURRENT_TYPE_NAME = TypeName; \
    static constexpr auto properties_() { return std::make_tuple(__VA_ARGS__); }
#define REFLECTABLE_MENBER_FUNCS(TypeName, ...) using CURRENT_TYPE_NAME = TypeName; \
    static constexpr auto member_funcs() { return std::make_tuple(__VA_ARGS__); }

// 这个宏用于创建属性信息,并自动将字段名转换为字符串
#define REFLEC_PROPERTY(Name) refl::Property<decltype(&CURRENT_TYPE_NAME::Name), &CURRENT_TYPE_NAME::Name>(#Name)
#define REFLEC_FUNCTION(Func) refl::Function<decltype(&CURRENT_TYPE_NAME::Func), &CURRENT_TYPE_NAME::Func>(#Func)

// 定义一个属性结构体,存储字段名称和值的指针
	template <typename T, T Value>
	struct Property {
		const char* name;
		constexpr Property(const char* name) : name(name) {}
		constexpr T get_value() const { return Value; }
	};
	template <typename T, T Value>
	struct Function {
		const char* name;
		constexpr Function(const char* name) : name(name) {}
		constexpr T get_func() const { return Value; }
	};

	// 使用 std::any 来处理不同类型的字段值和函数返回值
	template <typename T, typename Tuple, size_t N = 0>
	std::any __get_field_value_impl(T& obj, const char* name, const Tuple& tp) {
		if constexpr (N >= std::tuple_size_v<Tuple>) {
			return std::any();// Not Found!
		}
		else {
			const auto& prop = std::get<N>(tp);
			if (std::string_view(prop.name) == name) {
				return std::any(obj.*(prop.get_value()));
			}
			else {
				return __get_field_value_impl<T, Tuple, N + 1>(obj, name, tp);
			}
		}
	}

	// 使用 std::any 来处理不同类型的字段值和函数返回值
	template <typename T, size_t N = 0>
	std::any get_field_value(T* obj, const char* name) {
		return obj ? __get_field_value_impl(*obj, name, T::properties_()) : std::any();
	}

	// 使用 std::any 来处理不同类型的字段值和函数返回值
	template <typename T, typename Tuple, typename Value, size_t N = 0>
	std::any __assign_field_value_impl(T& obj, const char* name, const Value& value, const Tuple& tp) {
		if constexpr (N >= std::tuple_size_v<Tuple>) {
			return std::any();// Not Found!
		}
		else {
			const auto& prop = std::get<N>(tp);
			if (std::string_view(prop.name) == name) {
				if constexpr (std::is_assignable_v<decltype(obj.*(prop.get_value())), Value>) {
					obj.*(prop.get_value()) = value;
					return std::any(obj.*(prop.get_value()));
				}
				else {
					assert(false);// 无法赋值 类型不匹配!!
					return std::any();
				}
			}
			else {
				return __assign_field_value_impl<T, Tuple, Value, N + 1>(obj, name, value, tp);
			}
		}
	}
	template <typename T, typename Value>
	std::any assign_field_value(T* obj, const char* name, const Value& value) {
		return obj ? __assign_field_value_impl(*obj, name, value, T::properties_()) : std::any();
	}

	// 成员函数调用相关:
	template <bool assert_when_error = true, typename T, typename FuncTuple, size_t N = 0, typename... Args>
	constexpr std::any __invoke_member_func_impl(T& obj, const char* name, const FuncTuple& tp, Args&&... args) {
		if constexpr (N >= std::tuple_size_v<FuncTuple>) {
			assert(!assert_when_error);// 没找到!
			return std::any();// Not Found!
		}
		else {
			const auto& func = std::get<N>(tp);
			if (std::string_view(func.name) == name) {
				if constexpr (std::is_invocable_v<decltype(func.get_func()), T&, Args...>) {
					if constexpr (std::is_void<decltype(std::invoke(func.get_func(), obj, std::forward<Args>(args)...))>::value) {
						// 如果函数返回空,那么兼容这种case
						std::invoke(func.get_func(), obj, std::forward<Args>(args)...);
						return std::any();
					}
					else {
						return std::invoke(func.get_func(), obj, std::forward<Args>(args)...);
					}
				}
				else {
					assert(!assert_when_error);// 调用参数不匹配
					return std::any();
				}
			}
			else {
				return __invoke_member_func_impl<assert_when_error, T, FuncTuple, N + 1>(obj, name, tp, std::forward<Args>(args)...);
			}
		}
	}

	template <typename T, typename... Args>
	constexpr std::any invoke_member_func(T* obj, const char* name, Args&&... args) {
		constexpr auto funcs = T::member_funcs();
		return obj ? __invoke_member_func_impl(obj, name, funcs, std::forward<Args>(args)...) : std::any();
	}

	template <typename T, typename... Args>
	constexpr std::any invoke_member_func_safe(T* obj, const char* name, Args&&... args) {
		constexpr auto funcs = T::member_funcs();
		return obj ? __invoke_member_func_impl<true>(obj, name, funcs, std::forward<Args>(args)...) : std::any();
	}

	template <typename T, typename FuncPtr, typename FuncTuple, size_t N = 0>
	constexpr const char* __get_member_func_name_impl(FuncPtr func_ptr, const FuncTuple& tp) {
		if constexpr (N >= std::tuple_size_v<FuncTuple>) {
			return nullptr; // Not Found!
		}
		else {
			const auto& func = std::get<N>(tp);
			if constexpr (std::is_same< decltype(func.get_func()), FuncPtr >::value) {
				return func.name;
			}
			else {
				return __get_member_func_name_impl<T, FuncPtr, FuncTuple, N + 1>(func_ptr, tp);
			}
		}
	}

	template <typename T, typename FuncPtr>
	constexpr const char* get_member_func_name(FuncPtr func_ptr) {
		constexpr auto funcs = T::member_funcs();
		return __get_member_func_name_impl<T, FuncPtr>(func_ptr, funcs);
	}


	// 定义一个类型特征模板,用于获取属性信息
	template <typename T>
	struct For {
		static_assert(std::is_class_v<T>, "Reflector requires a class type.");

		// 遍历所有字段名称
		template <typename Func>
		static void for_each_propertie_name(Func&& func) {
			constexpr auto props = T::properties_();
			std::apply([&](auto... x) {
				((func(x.name)), ...);
				}, props);
		}

		// 遍历所有字段值
		template <typename Func>
		static void for_each_propertie_value(T* obj, Func&& func) {
			constexpr auto props = T::properties_();
			std::apply([&](auto... x) {
				((func(x.name, obj->*(x.get_value()))), ...);
				}, props);
		}

		// 遍历所有函数名称
		template <typename Func>
		static void for_each_member_func_name(Func&& func) {
			constexpr auto props = T::member_funcs();
			std::apply([&](auto... x) {
				((func(x.name)), ...);
				}, props);
		}
	};

	// ===============================================================

	// 以下是动态反射机制的支持代码:
	namespace dynamic {
		// 反射基类
		class IReflectable : public std::enable_shared_from_this<IReflectable> {
		public:
			virtual ~IReflectable() = default;
			virtual std::string_view get_type_name() const = 0;

			virtual std::any get_field_value_by_name(const char* name) const = 0;

			virtual std::any invoke_member_func_by_name(const char* name) = 0;
			virtual std::any invoke_member_func_by_name(const char* name, std::any param1) = 0;
			virtual std::any invoke_member_func_by_name(const char* name, std::any param1, std::any param2) = 0;
			virtual std::any invoke_member_func_by_name(const char* name, std::any param1, std::any param2, std::any param3) = 0;
			virtual std::any invoke_member_func_by_name(const char* name, std::any param1, std::any param2, std::any param3, std::any param4) = 0;
			// 不能无限增加,会增加虚表大小。最多支持4个参数的调用。
		};

		// 类型注册工具
		class TypeRegistry {
		public:
			using CreatorFunc = std::function<std::shared_ptr<IReflectable>()>;

			static TypeRegistry& instance() {
				static TypeRegistry registry;
				return registry;
			}

			void register_type(const std::string_view type_name, CreatorFunc creator) {
				creators_[type_name] = std::move(creator);
			}

			std::shared_ptr<IReflectable> create(const std::string_view type_name) {
				if (auto it = creators_.find(type_name); it != creators_.end()) {
					return it->second();
				}
				return nullptr;
			}

		private:
			std::unordered_map<std::string_view, CreatorFunc> creators_;
		};

		// 用于注册类型信息的宏
#define DECL_DYNAMIC_REFLECTABLE(TypeName) \
    friend class refl::dynamic::TypeRegistryEntry<TypeName>; \
    static std::string_view static_type_name() { return #TypeName; } \
    virtual std::string_view get_type_name() const override { return static_type_name(); } \
    static std::shared_ptr<::refl::dynamic::IReflectable> create_instance() { return std::make_shared<TypeName>(); } \
    static const bool is_registered; \
    std::any get_field_value_by_name(const char* name) const override { \
        return refl::get_field_value(this, name); \
    } \
    std::any invoke_member_func_by_name(const char* name) override { \
        return refl::invoke_member_func(static_cast<TypeName*>(this), name); \
    }\
	std::any invoke_member_func_by_name(const char* name, std::any param1) override { \
		return refl::invoke_member_func(static_cast<TypeName*>(this), name, param1); \
	}\
	std::any invoke_member_func_by_name(const char* name, std::any param1, std::any param2) override { \
		return refl::invoke_member_func(static_cast<TypeName*>(this), name, param1, param2); \
	}\
	std::any invoke_member_func_by_name(const char* name, std::any param1, std::any param2, std::any param3) override { \
		return refl::invoke_member_func(static_cast<TypeName*>(this), name, param1, param2, param3); \
	}\
	std::any invoke_member_func_by_name(const char* name, std::any param1, std::any param2, std::any param3, std::any param4) override { \
		return refl::invoke_member_func(static_cast<TypeName*>(this), name, param1, param2, param3, param4); \
	}\

	// 用于在静态区域注册类型的辅助类
		template <typename T>
		class TypeRegistryEntry {
		public:
			TypeRegistryEntry() {
				::refl::dynamic::TypeRegistry::instance().register_type(T::static_type_name(), &T::create_instance);
			}
		};

		// 为每个类型定义注册变量,这段宏需要出现在cpp中。
#define REGEDIT_DYNAMIC_REFLECTABLE(TypeName) \
    const bool TypeName::is_registered = [] { \
        static ::refl::dynamic::TypeRegistryEntry<TypeName> entry; \
        return true; \
    }();

	}//namespace dynamic


	//宏用于类中声明信号,并提供一个同名的方法来触发信号。宏参数是函数参数列表。示例:
	/*	void x_value_modified(int param) {
		IMPL_SIGNAL(param);
	}*/
#define REFLEC_IMPL_SIGNAL(...) raw_emit_signal_impl(__func__ , __VA_ARGS__)


	class CObject :
		public refl::dynamic::IReflectable {
	private:
		// 信号与槽的映射,键是信号名称,值是一组槽函数的信息
		using connections_list_type = std::list<std::tuple< std::weak_ptr<IReflectable>, std::string>>;
		using connections_type = std::unordered_map<std::string, connections_list_type>;
		connections_type connections_;

	public:
		template<typename... Args>
		void raw_emit_signal_impl(const char* signal_name, Args&&... args) {
			auto it = connections_.find(signal_name);
			if (it != connections_.end()) {
				auto& slots = it->second; // 获取槽信息列表的引用
				bool has_invalid_slot = false;
				for (const auto& slot_info : slots) {
					auto ptr = std::get<0>(slot_info).lock(); // 锁定弱引用
					if (ptr) {
						ptr->invoke_member_func_by_name(std::get<1>(slot_info).c_str(), std::forward<Args>(args)...);
					}
					else {
						has_invalid_slot = true;
					}
				}
				if (has_invalid_slot) {
					//如果存在无效对象,则执行一轮移除操作
					auto remove_it = std::remove_if(slots.begin(), slots.end(),
						[](const auto& slot_info) {
							return std::get<0>(slot_info).expired(); // 检查弱引用是否失效
						});
					slots.erase(remove_it, slots.end());
				}
			}
			else {/*没找到这个信号,要不要assert?*/ }
		}

		auto connect(const char* signal_name, refl::CObject* slot_instance, const char* slot_member_func_name) {
			if (!slot_instance || !signal_name || !slot_member_func_name) {
				throw std::runtime_error("param is null!");
			}
			assert(slot_instance->weak_from_this().lock());//target必须通过make_share构造!!因为要弱引用它

			std::string str_signal_name(signal_name);
			auto itMap = connections_.find(str_signal_name);
			if (itMap != connections_.end()) {
				itMap->second.emplace_back(slot_instance->weak_from_this(), slot_member_func_name);//必须插入末尾,因为返回了--end()迭代器指示这个链接
				return std::make_optional(std::make_tuple(this, itMap, --itMap->second.end()));
			}
			else {
				// 如果没找到,插入新元素到map中,并获取迭代器
				auto emplace_result = connections_.emplace(std::make_pair(std::move(str_signal_name), connections_list_type()));
				itMap = emplace_result.first;
				itMap->second.emplace_back(slot_instance->weak_from_this(), slot_member_func_name);
				return std::make_optional(std::make_tuple(this, itMap, --itMap->second.end()));
			}
		}
		template <typename SlotClass>
		auto connect(const char* signal_name, std::shared_ptr<SlotClass> slot_instance, const char* slot_member_func_name) {
			return connect(signal_name, slot_instance.get(), slot_member_func_name);
		}

		template <typename SignalClass, typename SignalType, typename SlotClass, typename SlotType>
		auto connect(SignalType SignalClass::* signal, SlotClass* slot_instance, SlotType SlotClass::* slot) {
			const char* signal_name = get_member_func_name<SignalClass>(signal);
			const char* slot_name = get_member_func_name<SlotClass>(slot);
			if (signal_name && slot_name) {
				return connect(signal_name, static_cast<CObject*>(slot_instance), slot_name);
			}
			throw std::runtime_error("signal name or slot_name is not found!");
		}
		template <typename SignalClass, typename SignalType, typename SlotClass, typename SlotType>
		auto connect(SignalType SignalClass::* signal, std::shared_ptr<SlotClass>& slot_instance, SlotType SlotClass::* slot) {
			return connect(signal, slot_instance.get(), slot);
		}

		template <typename T>
		bool disconnect(T connection) {
			//T是个这个类型:std::make_optional(std::make_tuple(this, itMap, it)); 由于T过于复杂,就直接用模板算了
			if (!connection) {
				return false;
			}
			auto& tuple = connection.value();
			if (std::get<0>(tuple) != this) {
				return false;//不是我的connection呀
			}
			std::get<1>(tuple)->second.erase(std::get<2>(tuple));
			return true;
		}

	};

	class QObject : public CObject {
	private:
		std::string objectName_;
		std::weak_ptr<refl::dynamic::IReflectable> parent_;
		std::unordered_map<std::string, std::any> properties_;
		std::list<std::shared_ptr<refl::dynamic::IReflectable>> children_;
	public:
		void setObjectName(const char* name) {
			objectName_ = name;
		}
		const std::string& getObjectName() {
			return objectName_;
		}

		void setParent(QObject* newParent) {
			if (auto oldParent = dynamic_cast<QObject*>(parent_.lock().get())) {
				auto it = std::find_if(oldParent->children_.begin(), oldParent->children_.end(),
					[this](const auto& child) { return child.get() == this; });
				if (it != oldParent->children_.end()) {
					oldParent->children_.erase(it);
				}
			}
			if (newParent) {
				parent_ = newParent->weak_from_this();
				newParent->children_.push_back(shared_from_this());
			}
			else {
				parent_.reset();
			}
		}
		template <typename T>
		void setParent(std::shared_ptr<T> newParent) {
			setParent(newParent.get());
		}

		void removeChild(CObject* child) {
			auto ch = static_cast<refl::dynamic::IReflectable*>(child);
			auto it = std::find_if(children_.begin(), children_.end(),
				[this, ch](const auto& child) { return child.get() == ch; });
			if (it != children_.end()) {
				children_.erase(it);
			}
		}
		CObject* findChild(const char* name) {
			for (auto child : children_) {
				QObject* qChild = dynamic_cast<QObject*>(child.get());
				if (qChild && qChild->objectName_ == name) {
					return qChild;
				}
			}
			return nullptr;
		}
		CObject* findChildRecursively(const char* name) {
			for (auto child : children_) {
				QObject* qChild = dynamic_cast<QObject*>(child.get());
				if (qChild) {
					if (qChild->objectName_ == name) {
						return qChild;
					}
					CObject* found = qChild->findChildRecursively(name);
					if (found) {
						return found;
					}
				}
			}
			return nullptr;
		}

		const std::any& getProperty(const char* name) {
			return properties_[name];
		}
		template<typename T>
		const T* getProperty(const char* name) {
			try {
				return &std::any_cast<const T&>(properties_[name]);
			}
			catch (...) {
				return nullptr;
			}
		}
		void setProperty(const char* name, const std::any& value) {
			properties_[name] = value;
		}

	};




	class CEventLoop {
	public:
		using Clock = std::chrono::steady_clock;
		using TimePoint = Clock::time_point;
		using Duration = Clock::duration;
		using Handler = std::function<void()>;
		struct TimedHandler {
			TimePoint time;
			Handler handler;
			bool operator<(const TimedHandler& other) const {
				return time > other.time;
			}
		};
		class IEventLoopHost {
		public:
			virtual void onWaitForTask(std::condition_variable& cond, std::unique_lock<std::mutex>& locker) = 0;
			virtual void onEvent(TimedHandler& event) = 0;
			virtual void onWaitForRun(std::condition_variable& cond, std::unique_lock<std::mutex>& locker, const TimePoint& timePoint) = 0;
		};
	private:
		IEventLoopHost* host = nullptr;
		std::priority_queue<TimedHandler> tasks_;
		std::mutex mutex_;
		std::condition_variable cond_;
		std::atomic<bool> running_{ true };

	public:
		void setHost(IEventLoopHost* host) {
			this->host = host;
		}
		void post(Handler handler, Duration delay = Duration::zero()) {
			std::unique_lock<std::mutex> lock(mutex_);
			tasks_.push({ Clock::now() + delay, std::move(handler) });
			cond_.notify_one();
		}

		void run() {
			while (running_) {
				std::unique_lock<std::mutex> lock(mutex_);
				if (tasks_.empty()) {
					if (host) {
						host->onWaitForTask(cond_, lock);
					}
					else {
						cond_.wait(lock, [this] { return !tasks_.empty() || !running_; });
					}
				}

				while (!tasks_.empty() && tasks_.top().time <= Clock::now()) {
					auto task = tasks_.top();
					tasks_.pop();
					lock.unlock();
					if (host) {
						host->onEvent(task);
					}
					else {
						task.handler();
					}

					lock.lock();
				}

				if (!tasks_.empty()) {
					if (host) {
						host->onWaitForRun(cond_, lock, tasks_.top().time);
					}
					else {
						cond_.wait_until(lock, tasks_.top().time);
					}
				}
			}
		}

		void stop() {
			running_ = false;
			cond_.notify_all();
		}

	};


}// namespace refl


// =========================一下为使用示例代码====================================

// 用户自定义的结构体
class MyStruct :
	//public refl::dynamic::IReflectable 	// 如果不需要动态反射,可以不从public refl::dynamic::IReflectable派生
	public refl::QObject // 这里我们也测试信号槽等功能,因此从这个类派生
{

public:
	~MyStruct() {
		std::cout << getObjectName() << " destoryed " << std::endl;
	}
	int x{ 10 };
	double y{ 20.5f };
	int print() const {
		std::cout << "MyStruct::print called! " << "x: " << x << ", y: " << y << std::endl;
		return 666;
	}
	// 如果需要支持动态调用,参数必须是std::any,并且不能超过4个参数。
	int print_with_arg(std::any param) const {
		std::cout << "MyStruct::print called! " << " arg is: " << std::any_cast<int>(param) << std::endl;
		return 888;
	}
	// 定义一个方法,用作槽函数,必须在REFLECTABLE_MENBER_FUNCS列表中,不支持返回值,并且参数必须是std::any,不能超过4个参数。
	std::any on_x_value_modified(std::any& new_value) {
		int value = std::any_cast<int>(new_value);
		std::cout << "MyStruct::on_x_value_modified called! New value is: " << value << std::endl;
		return 0;
	}

	void x_value_modified(std::any param) {
		REFLEC_IMPL_SIGNAL(param);
	}

	REFLECTABLE_PROPERTIES(MyStruct,
		REFLEC_PROPERTY(x),
		REFLEC_PROPERTY(y)
	);
	REFLECTABLE_MENBER_FUNCS(MyStruct,
		REFLEC_FUNCTION(print),
		REFLEC_FUNCTION(print_with_arg),
		REFLEC_FUNCTION(on_x_value_modified),
		REFLEC_FUNCTION(x_value_modified)
	);

	DECL_DYNAMIC_REFLECTABLE(MyStruct)//动态反射的支持,如果不需要动态反射,可以去掉这行代码
};

//动态反射注册类,注册创建工厂
REGEDIT_DYNAMIC_REFLECTABLE(MyStruct)


int main() {

	// 静态反射部分:
	std::cout << "---------------------静态反射部分:" << std::endl;

	auto obj = std::make_shared<MyStruct>();
	// 打印所有字段名称
	refl::For<MyStruct>::for_each_propertie_name([](const char* name) {
		std::cout << "Field name: " << name << std::endl;
		});

	// 打印所有字段值
	refl::For<MyStruct>::for_each_propertie_value(obj.get(), [](const char* name, auto&& value) {
		std::cout << "Field " << name << " has value: " << value << std::endl;
		});

	// 打印所有函数名称
	refl::For<MyStruct>::for_each_member_func_name([](const char* name) {
		std::cout << "Member func name: " << name << std::endl;
		});

	// 获取特定成员的值,如果找不到成员,则返回默认值
	auto x_value = refl::get_field_value(obj.get(), "x");
	std::cout << "Field x has value: " << std::any_cast<int>(x_value) << std::endl;

	auto y_value = refl::get_field_value(obj.get(), "y");
	std::cout << "Field y has value: " << std::any_cast<double>(y_value) << std::endl;

	//修改值:
	refl::assign_field_value(obj.get(), "y", 33.33f);
	y_value = refl::get_field_value(obj.get(), "y");
	std::cout << "Field y has modifyed,new value is: " << std::any_cast<double>(y_value) << std::endl;

	auto z_value = refl::get_field_value(obj.get(), "z"); // "z" 不存在
	if (z_value.type().name() == std::string_view("int")) {
		std::cout << "Field z has value: " << std::any_cast<int>(z_value) << std::endl;
	}

	// 通过字符串调用成员函数 'print'
	auto print_ret = refl::invoke_member_func_safe(obj.get(), "print");
	std::cout << "print member return: " << std::any_cast<int>(print_ret) << std::endl;


	std::cout << "---------------------动态反射部分:" << std::endl;

	// 动态反射部分(动态反射完全不需要知道类型MyStruct的定义):
	// 动态创建 MyStruct 实例并调用方法
	auto instance = refl::dynamic::TypeRegistry::instance().create("MyStruct");
	if (instance) {
		std::cout << "Dynamic instance type: " << instance->get_type_name() << std::endl;
		// 这里可以调用 MyStruct 的成员方法
		auto x_value2 = instance->get_field_value_by_name("x");
		std::cout << "Field x has value: " << std::any_cast<int>(x_value2) << std::endl;

		instance->invoke_member_func_by_name("print");
		instance->invoke_member_func_by_name("print_with_arg", 10);
		//instance->invoke_member_func_by_name("print_with_arg", 20, 222);//这个调用会失败,命中断言,因为print_with_arg只接受一个函数
	}

	// 信号槽部分:
	std::cout << "---------------------信号槽部分:" << std::endl;

	auto obj1 = std::make_shared<MyStruct>();
	obj1->setObjectName("obj1");
	auto obj2 = std::make_shared<MyStruct>();
	obj2->setObjectName("obj2");
	obj2->setParent(obj1);

	// 连接obj1的信号到obj2的槽函数
	auto connection_id = obj1->connect("x_value_modified", obj2.get(), "on_x_value_modified");
	if (!connection_id) {
		std::cout << "Signal x_value_modified from obj1 connected to on_x_value_modified slot in obj2." << std::endl;
	}

	obj1->x_value_modified(42);// 触发信号
	// 断开连接
	obj1->disconnect(connection_id);
	// 再次触发信号,应该没有任何输出,因为已经断开连接
	obj1->x_value_modified(84);

	// 使用成员函数指针版本的connect
	connection_id = obj1->connect(&MyStruct::x_value_modified, obj2, &MyStruct::on_x_value_modified);
	if (!connection_id) {
		std::cout << "Signal connected to slot." << std::endl;
	}
	obj1->x_value_modified(666);// 触发信号

	obj2.reset();
	obj1.reset();

	
	// 事件循环部分:
	std::cout << "---------------------事件循环部分:" << std::endl;
	refl::CEventLoop loop;
	loop.post([]() {
		std::cout << "Immediate task\n";
		});//马上执行

	loop.post([]() {
		std::cout << "Delayed task\n";
		}, std::chrono::seconds(1));//延时一秒

	std::thread loop_thread([&loop]() {
		loop.run();
		});

	std::this_thread::sleep_for(std::chrono::seconds(2));
	loop.stop();//停止消息循环
	loop_thread.join();


	std::cout << "====end=====" << std::endl;
	return 0;
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/775854.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RAM和ROM的区别

RAM和ROM的区别 RAM和ROM都是用来存东西的&#xff0c;比如我们熟悉的CPU缓存、电脑和手机的内存就是属于RAM&#xff0c;而固态硬盘、U盘&#xff0c;还有我们买手机时候说的32G、64G的存储空间&#xff0c;就属于ROM。RAM和ROM的区别&#xff0c;简单说就是RAM在断电之后&am…

前端面试题12(js异步方法)

在JavaScript中&#xff0c;异步编程是处理延迟操作&#xff08;如网络请求、定时器等&#xff09;的关键方式&#xff0c;它允许代码在等待某些操作完成时继续执行&#xff0c;提高了应用的响应性和用户体验。 回调函数&#xff08;Callback&#xff09; 回调是最原始的异步处…

spark shuffle写操作——BypassMergeSortShuffleWriter

创建分区文件writer 每一个分区都生成一个临时文件&#xff0c;创建DiskBlockObjectWriter对象&#xff0c;放入partitionWriters 分区writer写入消息 遍历所有消息&#xff0c;每一条消息都使用分区器选择对应分区的writer然后写入 生成分区文件 将分区writer的数据flu…

用html+css设计一个列表清单小卡片

目录 简介: 效果图: 源代码: 可能的问题: 简介: 这个HTML代码片段是一个简单的列表清单设计。它包含一个卡片元素(class为"card"),内部包含一个无序列表(ul),列表项(li)前面有一个特殊的符号(△)。整个卡片元素设计成300px宽,150px高,具有圆角边…

【字符串】【滑动窗口+位运算+双指针】1、无重复字符的最长子串+2、尽可能使字符串相等+3、最长优雅子数组+4、移动零+5、反转字符串

2道简单3道中等 1、无重复字符的最长子串&#xff08;难度&#xff1a;中等&#xff09; 该题对应力扣网址 超时代码 老实说&#xff0c;在我写博客的时候&#xff0c;也不知道为啥超时了&#xff0c;因为我看和我AC的代码时间也差不了多少吧&#xff08;如果有大佬知道&…

误删分区后的数据拯救:双管齐下恢复策略

在数字化时代&#xff0c;数据的价值日益凸显&#xff0c;而误删分区作为常见的数据安全威胁之一&#xff0c;常常让用户措手不及。本文将深入探讨误删分区的现象&#xff0c;并为您揭示两种高效的数据恢复方案&#xff0c;旨在帮助您在最短时间内找回失去的数据&#xff0c;同…

1117 数字之王

solution 判断现有数字是否全为个位数 全为个位数&#xff0c;找出出现次数最多的数字&#xff0c;并首行输出最多出现次数&#xff0c;第二行输出所有出现该次数的数值不全为个位数 若当前位数值为0&#xff0c;无需处理若当前位数值非0&#xff0c;则每位立方相乘&#xff0…

Linux搭建hive手册

一、将hive安装包上传到NameNode节点并解压 1、删除安装MySQL时的.rpm文件 cd /opt/install_packages/ rm -rf *.rpm 2、将安装包拖进/install_packages目录 3、解压安装包 tar -zxvf apache-hive-3.1.2-bin.tar.gz -C /opt/softs/ 4、修改包名 cd /opt/softs mv apache-…

虚拟机下基于海思移植QT(一)——虚拟机下安装QT

0.参考资料 1.海思Hi3516DV300 移植Qt 运行并在HDMI显示器上显示 2.搭建海思3559A-Qt4.8.7Openssl开发环境 1.报错解决 通过下面命令查询 strings /lib/x86_64-linux-gnu/libc.so.6 | grep GLIBC_通过命令行没有解决&#xff1a; sudo apt install libc6-dev libc6参考解决…

【国产开源可视化引擎Meta2d.js】锚点

国产开源 乐吾乐潜心研发&#xff0c;自主可控&#xff0c;持续迭代优化 Github&#xff1a;GitHub - le5le-com/meta2d.js: The meta2d.js is real-time data exchange and interactive web 2D engine. Developers are able to build Web SCADA, IoT, Digital twins and so …

【C语言题目】34.猜凶手

文章目录 作业标题作业内容2.解题思路3.具体代码 作业标题 猜凶手 作业内容 日本某地发生了一件谋杀案&#xff0c;警察通过排查确定杀人凶手必为4个嫌疑犯的一个。 以下为4个嫌疑犯的供词: A说&#xff1a;不是我。 B说&#xff1a;是C。 C说&#xff1a;是D。 D说&#xff…

软件是什么?一个软件到底是哪些部分组成的-软件到底有哪些分支呢?

https://doc.youyacao.com/117/2163 软件是什么&#xff1f;一个软件到底是哪些部分组成的-软件到底有哪些分支呢&#xff1f; 何为软件 软件定义 的本质是通过软件编程实现硬件资源的虚拟化、灵活、多样和定制化功能&#xff0c;以最大化系统运行效率和能量效率。它基于硬…

SSM中小学生信息管理系统-计算机毕业设计源码02677

摘要 随着社会的发展和教育的进步&#xff0c;中小学生信息管理系统成为学校管理的重要工具。本论文旨在基于SSM框架&#xff0c;采用Java编程语言和MySQL数据库&#xff0c;设计和开发一套高效、可靠的中小学生信息管理系统。中小学生信息管理系统以学生为中心&#xff0c;通过…

H2 Database Console未授权访问漏洞封堵

背景 H2 Database Console未授权访问&#xff0c;默认情况下自动创建不存在的数据库&#xff0c;从而导致未授权访问。各种未授权访问的教程&#xff0c;但是它怎么封堵呢&#xff1f; -ifExists 很简单&#xff0c;启动参数添加 -ifExists &#xff0c;它的含义&#xff1a…

漏洞分析 | PHP CGI Windows平台远程代码执行漏洞(CVE-2024-4577)

漏洞概述 PHP CGI&#xff08;Common Gateway Interface&#xff09;是在Windows平台上运行PHP的一种方式。CGI是一种标准接口&#xff0c;允许Web服务器与外部应用程序&#xff08;如PHP脚本&#xff09;进行交互&#xff0c;从而生成动态网页内容。 近期&#xff0c;PHP发布…

STMCUBEMX_IIC_LL库_AT24C64分页读取和写入

STMCUBEMX_IIC_LL库_AT24C64分页读取和写入 前言&#xff1a; 一个项目中构建的软件系统需要存储非常多的用户参数&#xff0c;大约有几千字节&#xff0c;所以牵扯到自己设计跨页写入算法&#xff0c;注意读出也是需要设计跨页读出算法的&#xff08;手册没强调&#xff0c;但…

二、从多臂老虎机看强化学习

二、从多臂老虎机看强化学习 2.1 多臂老虎机问题2.1.1 问题定义2.2.2 问题建模2.2.3 累积懊悔2.2.4 估计期望奖励 2.2 强化学习中的探索与利用平衡2.3 贪心策略2.4 上置信界算法2.5 汤普森采样算法 2.1 多臂老虎机问题 2.1.1 问题定义 在多臂老虎机(mutil-armed bandit, MAB)问…

专业电脑录歌软件,电脑录音的六大方法【你了解几个】

电脑录音怎么录&#xff1f;大多数电脑都是有自带的录音功能的&#xff0c;但是由于电脑系统自带的录音功能效果没那么好&#xff0c;很多情况下满足不了我们一些“刁钻”的录音需求。 那么电脑怎么录音&#xff1f;还有哪些好用的录音软件推荐&#xff1f;本文整理了多种电脑录…

常规情况与opencv图像中,计算直线与矩形框的交点

文章目录 1、普通方式1.1、普通计算过程1.2、优化方式 2、图像中的情况2.1、常规处理2.2、opencv中的处理2.2.1、cv::clipLine函数2.2.2、测试代码2.2.3、测试结果 1、普通方式 已知矩形框左上(x1,y1)、右下(x2,y2&#xff09;点&#xff0c;直线方程 y kxb&#xff0c;求交点…

桌面保存的Word文件删除怎么找回?超实用的三个方法?

在日常工作和学习中&#xff0c;我们经常会使用Word文档进行文字编辑和文件保存。但是&#xff0c;有时由于操作失误或系统故障&#xff0c;我们会不小心将存放在电脑桌面重要的Word文件删除了。导致无法挽回的损失&#xff0c;但幸运的是&#xff0c;有一些方法可以帮助我们找…