Skip to content

Conversation

@mingxwa
Copy link
Member

@mingxwa mingxwa commented Sep 1, 2025

Changes

  • Fixed the definition of details::observer_indirect_conv to honor the facade-aware overloads without early substitution.
  • Refactored details::observer_facade_conv_impl and details::observer_facade_refl_impl accordingly with composite_t.
  • Added a unit test case for this scenario.

Resolves #346

@DannyBaobei
Copy link

passed by the bellowing code

#include <iostream>

#include "proxy/proxy.h"
#define ADAPTER_GENERIC_GETTER(name)                            \
    template <typename T>                                       \
    static double name(const T& ptr) {                          \
        if constexpr (requires { ptr.name(); }) {              \
            return ptr.name();                                 \
        } else if constexpr (requires { ptr.name##_; }) {      \
            return ptr.name##_;                                \
        } else {                                                \
            static_assert(false, "No compatible getter found"); \
        }                                                       \
    }

#define ADAPTER_GENERIC_SETTER(name)                               \
    template <typename T>                                          \
    static void set_##name(T& ptr, double value) {                 \
        if constexpr (requires { ptr.set_##name(value); }) {      \
            ptr.set_##name(value);                                \
        } else if constexpr (requires { ptr.name##_ = value; }) { \
            ptr.name##_ = value;                                  \
        } else {                                                   \
            static_assert(false, "No compatible setter found");    \
        }                                                          \
    }



#define ADAPTER_GENERIC_ACCESSOR(name) \
    ADAPTER_GENERIC_GETTER(name)       \
    ADAPTER_GENERIC_SETTER(name)
namespace  mid
{
	namespace basic_facade
	{
		struct Point_2
		{
			double x_, y_;

			Point_2() = default;

			explicit Point_2(double x, double y) : x_(x), y_(y)
			{
			}

			bool AreEqual(const Point_2& rhs, double eps) const
			{
				return std::abs(x_ - rhs.x_) < eps && std::abs(y_ - rhs.y_) < eps;
			}

			// IPoint_2 facade required methods
			double x() const
			{
				return x_;
			}

			double y() const { return y_; }

			void set_x(double value)
			{
				x_ = value;
			}

			void set_y(double value)
			{
				y_ = value;
			}
		};

		




		// 1. Define the overload signature for the AreEqual method.
		//    It will take another proxy object (via proxy_indirect_accessor).
		template <class F>
		using AreEqualOverload = bool(const pro::proxy_indirect_accessor<F>& rhs, double eps) const;

		namespace adapter
		{
	
			struct point_adapter
			{
				ADAPTER_GENERIC_ACCESSOR(x)
				ADAPTER_GENERIC_ACCESSOR(y)
				// 2. Implement the dispatch function. This free function will be called by the proxy.
	//    It casts the proxy `rhs` back to the concrete type `T` and calls the member function.
				template <class T, pro::facade F>
				static bool AreEqualImpl(const T& lhs, const pro::proxy_indirect_accessor<F>& rhs, double eps)
				{
					return lhs.AreEqual(proxy_cast<const T&>(rhs), eps);
				}
			};
		

		}
		PRO_DEF_FREE_AS_MEM_DISPATCH(MemX, adapter::point_adapter::x, x);
		PRO_DEF_FREE_AS_MEM_DISPATCH(MemY, adapter::point_adapter::y, y);
		PRO_DEF_FREE_AS_MEM_DISPATCH(MemSetX, adapter::point_adapter::set_x, set_x);
		PRO_DEF_FREE_AS_MEM_DISPATCH(MemSetY, adapter::point_adapter::set_y, set_y);
		PRO_DEF_FREE_AS_MEM_DISPATCH(MemAreEqual, adapter::point_adapter::AreEqualImpl, AreEqual);

		struct IPoint_2 : pro::facade_builder
			::add_skill<pro::skills::rtti> // for proxy_cast
			//::support_copy<pro::constraint_level::nontrivial>
			::add_convention<MemX, double() const>
			::add_convention<MemY, double() const>
			::add_convention<MemSetX, void(double)>
			::add_convention<MemSetY, void(double)>
			::add_convention<MemAreEqual, pro::facade_aware_overload_t<AreEqualOverload>>
			::build
		{
		};


		using MPointProxy = pro::proxy<IPoint_2>;

		 
	}

} // namespace mid
int main()
{
	using namespace mid::basic_facade;
	Point_2 raw_p0{0.0, 0.0};
	raw_p0.x_ = 1.0;
	raw_p0.y_ = 2.0;
	Point_2 raw_p1 = raw_p0;
	MPointProxy proxy_p0 = &raw_p0;
	MPointProxy proxy_p1 = &raw_p1;
	proxy_p0->set_x(5.0);
	proxy_p0->set_y(7.0);
	

 	bool ret = proxy_p0->AreEqual(*proxy_p1, 1.0e-9);
	std::cout << "AreEqual: " << ret << std::endl;


	auto proxy_p10 = pro::make_proxy_view<IPoint_2>(raw_p0);
	auto proxy_p11 = pro::make_proxy_view<IPoint_2>(raw_p1);
	proxy_p11->set_x(5.0);
	proxy_p11->set_y(7.0);
	ret = proxy_p10->AreEqual(*proxy_p11, 1.0e-9);
	std::cout << "AreEqual: " << ret << std::endl;
	
}

@mingxwa mingxwa merged commit 7f11ac5 into microsoft:main Sep 1, 2025
10 checks passed
@mingxwa mingxwa deleted the user/mingxwa/facade-aware-proxy-view branch September 1, 2025 07:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

How to declare a self implement binary operation like "bool AreEqual(const Point_2& other, double tol=1.0e-6)"?

3 participants