From a672f37fae9182c83b0dc108d572786529383fba Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Wed, 12 Aug 2026 01:44:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E5=AE=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 + README.zh-CN.md | 2 + core/include/structive/property/accessor.hpp | 40 ++++++++++++++++++++ core/include/structive/property/schema.hpp | 3 ++ core/tests/property_core_test.cpp | 11 ++++++ 5 files changed, 58 insertions(+) diff --git a/README.md b/README.md index a1aa493..c110c2e 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,8 @@ read_write For normal accessors Structive derives this from the accessor automatically. A member field is normally `read_write`; a getter-only computed property is naturally `read`. +`Member_Accessor` is the default for stored members. When an object exposes a property through business methods or a child control, `trusted_callable_accessor(reader, writer)` supplies that access strategy while consumers continue to use the same `Property_Accessor` protocol without mirrored object state. + The schema can explicitly narrow the capability: ```cpp diff --git a/README.zh-CN.md b/README.zh-CN.md index 42f133d..17bfa74 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -96,6 +96,8 @@ read_write 正常情况下由 Accessor 自动推导。普通可写成员天然是 `read_write`,getter-only computed property 天然是 `read`。 +`Member_Accessor` 是数据成员的默认实现。对象通过业务方法或子控件暴露属性时,可用 `trusted_callable_accessor(reader, writer)` 传入具体访问策略;调用方仍消费统一的 `Property_Accessor` 协议,不需要复制对象状态或增加转发成员。 + Schema 可以显式收窄能力: ```cpp diff --git a/core/include/structive/property/accessor.hpp b/core/include/structive/property/accessor.hpp index e333307..6e427ba 100644 --- a/core/include/structive/property/accessor.hpp +++ b/core/include/structive/property/accessor.hpp @@ -140,6 +140,46 @@ struct Trusted_Getter_Setter_Accessor { std::invoke(Setter, object, std::forward(value)); } }; +template +requires std::invocable && + (!std::is_void_v>) && + (!std::is_rvalue_reference_v>) && + std::invocable>> && + std::same_as>>, + void> +struct Trusted_Callable_Accessor { + using object_type = Object; + using value_type = + std::remove_cvref_t>; + using storage_identity = void; + static constexpr bool readable = true; + static constexpr bool writable = true; + static constexpr bool synchronized_view_read = false; + static constexpr bool trusted_object_access = true; + using dependency_spec = No_Property_Dependencies; + + [[no_unique_address]] Reader reader; + [[no_unique_address]] Writer writer; + + constexpr decltype(auto) read(const object_type& object) const + noexcept(std::is_nothrow_invocable_v) { + return std::invoke(reader, object); + } + template + constexpr void write(object_type& object, Value&& value) const + requires std::invocable && + std::same_as, void> { + std::invoke(writer, object, std::forward(value)); + } +}; +template +auto trusted_callable_accessor(Reader reader, Writer writer) { + return Trusted_Callable_Accessor{ + std::move(reader), std::move(writer)}; +} template concept Property_Accessor = requires { typename Accessor::object_type; diff --git a/core/include/structive/property/schema.hpp b/core/include/structive/property/schema.hpp index da2ab4b..f7af033 100644 --- a/core/include/structive/property/schema.hpp +++ b/core/include/structive/property/schema.hpp @@ -556,6 +556,9 @@ auto object_schema(Properties&&... properties) requires (Property_Descriptor_Typ return make_object_schema(no_defaults, Synchronization_Plan{}, std::forward(properties)...); } template +requires requires(Arguments&&... arguments) { + object_schema(std::forward(arguments)...); +} auto object(Arguments&&... arguments) { return object_schema(std::forward(arguments)...); } diff --git a/core/tests/property_core_test.cpp b/core/tests/property_core_test.cpp index 3938bfd..6c70d34 100644 --- a/core/tests/property_core_test.cpp +++ b/core/tests/property_core_test.cpp @@ -131,6 +131,9 @@ struct Pure_Read_Only_Device : Property_Object { int id{21}; int version{4}; }; +struct Callable_Device { + int value{4}; +}; template <> struct structive::Type_Descriptor { static auto get() { @@ -184,6 +187,14 @@ static void runtime_read_int(void* context, std::size_t, std::string_view, const *static_cast(context) = *static_cast(value); } int main() { + auto callable_accessor = trusted_callable_accessor( + [](const Callable_Device& value) { return value.value; }, + [](Callable_Device& target, int value) { target.value = value; }); + static_assert(Property_Accessor); + Callable_Device callable_device; + REQUIRE(callable_accessor.read(callable_device) == 4); + callable_accessor.write(callable_device, 9); + REQUIRE(callable_device.value == 9); static_assert(Property_Described_Object); static_assert(!Can_Write_Immutable); static_assert(!Can_Write_Immutable_By_Key);