#pragma once #include #include // 少量样板代码的生成宏是可以接受的, // 等 concept 可以作为参数的那一天,这个宏就可以废弃了 #define CREEPER_DEFINE_CHECKER(TRAIT) \ struct checker final { \ template \ static constexpr bool result = TRAIT; \ }; namespace creeper { /// CHECKER template concept checker_trait = requires { { T::template result }; }; template struct CheckerOr { template static constexpr bool result = (Ts::template result || ...); }; template struct CheckerAnd { template static constexpr bool result = (Ts::template result && ...); }; /// PROP template struct SetterProp : Token { T value; constexpr explicit SetterProp(T value) noexcept : value { std::move(value) } { } constexpr explicit operator T(this auto&& self) noexcept { return self.value; } template auto operator=(O&& other) noexcept -> SetterProp& requires std::assignable_from { value = std::forward(other); return *this; // x= y =6 } auto apply(auto& self) const noexcept -> void requires requires { interface(self, std::declval()); } { interface(self, value); } }; template struct DerivedProp : T, Token { using T::T; template requires std::constructible_from constexpr explicit DerivedProp(Args&&... args) : T(std::forward(args)...) { } template requires requires(T& t, U&& u) { t = std::forward(u); } auto operator=(U&& value) -> DerivedProp& { T::operator=(std::forward(value)); return *this; } auto apply(this auto const& self, auto& widget) noexcept -> void { interface(widget, static_cast(self)); } }; template struct ActionProp : Token { auto apply(auto& self) const noexcept -> void requires requires { interface(self); } { interface(self); } }; /// @brief /// 声明式包装,非侵入式实现 Setter 的声明式化 /// /// 该包装器支持将 std::tuple 与单个 prop 混合传入,不受顺序限制。内部通过 /// helper 检查 tuple 中的所有元素,递归调用 apply 将属性应用到 底层 Widget。 /// 利用 CheckerT 延迟模板实例化,在 concept 层面约束属性类型, 从而避免因 /// 递归参数展开而产生的海量且难以定位的模板错误。 /// /// @tparam W /// 需要被包装的组件类型。 /// /// @tparam checker /// 用于延迟模板实例化的“检查器”类型模板。典型形式如下: /// struct checker final { /// template struct result { /// static constexpr auto v = concept; /// }; /// }; /// /// @note /// 在不符合 checker 要求的类型被传入时,会在 concept 约束阶段直接报错, /// 提供简洁且精准的编译期错误提示,避免编译器自动展开大量构造函数 /// 导致的冗长错误栈,但编译期报错信息依旧不友好。 /// template struct Declarative : public W { private: // For helpe check single props // 这里没法子塞一个 static_assert,无论如何这里都会被尝试错误地实例化 template static constexpr auto impl_props_trait = checker_::template result>; // For help check tuple of props // 使用 SFINAE 真是抱歉,没找到方便处理 tuple 的方法真是不好意思呢 template static constexpr auto impl_tuple_trait = false; template static constexpr auto impl_tuple_trait, checker_> = (impl_props_trait && ...); public: /* Export widget type */ using Widget = W; /* Export checker type */ using Checker = checker; /* For check props */ template static constexpr auto props_trait = impl_props_trait, checker>; /* For check tuple */ template static constexpr auto tuple_trait = impl_tuple_trait, checker>; public: // 铁血的,热血的,冷血的声明式构造接口 explicit Declarative(auto&&... props) noexcept requires((props_trait || tuple_trait) && ...) : W {} { (apply(std::forward(props)), ...); } auto apply(auto&& tuple) noexcept -> void requires tuple_trait { std::apply([this](auto&&... args) { (apply(std::forward(args)), ...); }, std::forward(tuple)); } auto apply(auto&& prop) noexcept -> void requires props_trait { std::forward(prop).apply(*this); } }; }