microsoft / proxy

Proxy: Next Generation Polymorphism in C++

Home Page:https://wg21.link/p3086

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to create a proxy object that is composed of another proxy object of the same type?

revtronix opened this issue · comments

Is there a way to create a proxy object that is composed of another proxy object of the same type? This could be used to create a UI hierarchy for example.

The following example doesn't compile, but can compile once the drawable member variable of Rectangle is removed.

// Abstraction
struct Draw : pro::dispatch<void()> {
	template <class T>
	void operator()(const T& self) { self.draw(); }
};

struct DrawableFacade : pro::facade<Draw> {};

// Implementation
class Rectangle {
public:
	void draw() const {
		drawable.invoke();
	};

	pro::proxy<DrawableFacade> drawable;
};

// Client - Producer
pro::proxy<DrawableFacade> CreateRectangleAsDrawable(int width, int height) {
	Rectangle rect;
	return pro::make_proxy<DrawableFacade>(rect);
}

Here is the error output when compiled in VS2022 17.8.1:

.\proxy\proxy.h(273): error C2131: expression did not evaluate to a constant
  ...\proxy\proxy.h(273): note: failure was caused by a read of an uninitialized symbol
  ...\proxy\proxy.h(273): note: see usage of 'pro::proxiable<pro::details::deep_ptr<Rectangle>,DrawableFacade>'
  ...\proxy\proxy.h(273): note: the template instantiation context (the oldest one first) is
  ...\layout.cpp(61): note: see reference to function template instantiation 'pro::proxy<DrawableFacade> pro::make_proxy<DrawableFacade,Rectangle&>(T)' being compiled
          with
          [
              T=Rectangle &
          ]
  ...\proxy\proxy.h(521): note: see reference to function template instantiation 'pro::proxy<DrawableFacade> pro::details::make_proxy_impl<DrawableFacade,Rectangle,Rectangle&>(Rectangle &)' being compiled
  ...\proxy\proxy.h(343): note: see reference to variable template 'const bool pro::proxy<DrawableFacade>::HasPolyConstructor<pro::details::deep_ptr<Rectangle>,Rectangle &>' being compiled
  ...\proxy\proxy.h(273): note: see reference to variable template 'bool proxiable<pro::details::deep_ptr<Rectangle>,DrawableFacade>' being compiled
  ...\proxy\proxy.h(260): note: see reference to variable template 'const bool pro::details::facade_traits_impl<DrawableFacade,std::tuple<Draw> >::applicable_pointer<pro::details::deep_ptr<Rectangle> >' being compiled
  ...\proxy\proxy.h(238): note: see reference to function template instantiation 'bool pro::details::has_copyability<pro::details::deep_ptr<Rectangle>>(pro::constraint_level)' being compiled
  ...\proxy\proxy.h(50): note: see reference to variable template 'const bool is_trivially_copy_constructible_v<pro::details::deep_ptr<Rectangle> >' being compiled
  ...\proxy\proxy.h(491): note: see reference to variable template 'const bool is_constructible_v<Rectangle,pro::details::deep_ptr<Rectangle> const &>' being compiled
  ...\proxy\proxy.h(338): note: see reference to variable template 'const bool pro::proxy<DrawableFacade>::HasPolyConstructor<pro::details::deep_ptr<Rectangle>,pro::details::deep_ptr<Rectangle> const &>' being compiled
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtr1common(69): error C2131: expression did not evaluate to a constant
  C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtr1common(69): note: failure was caused by a read of an uninitialized symbol
  C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtr1common(69): note: see usage of 'pro::proxiable<pro::details::deep_ptr<Rectangle>,DrawableFacade>'
  C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtr1common(69): note: the template instantiation context (the oldest one first) is
  ...\proxy\proxy.h(272): note: see reference to alias template instantiation 'std::conditional_t<pro::proxiable<pro::details::deep_ptr<Rectangle>,DrawableFacade>,std::is_constructible<pro::details::deep_ptr<Rectangle>,const pro::details::deep_ptr<Rectangle> &>,std::integral_constant<bool,false>>' being compiled
...\proxy\proxy.h(506): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'pro::proxy<DrawableFacade>'
  ...\proxy\proxy.h(506): note: 'pro::proxy<DrawableFacade>::proxy': function does not take 2 arguments
  ...\proxy\proxy.h(346): note: could be 'pro::proxy<DrawableFacade>::proxy(std::in_place_type_t<_Ty>,std::initializer_list<_Elem>,Args &&...) noexcept(<expr>)'
  ...\proxy\proxy.h(341): note: or       'pro::proxy<DrawableFacade>::proxy(std::in_place_type_t<_Ty>,Args &&...) noexcept(<expr>)'
  ...\proxy\proxy.h(337): note: or       'pro::proxy<DrawableFacade>::proxy(P &&) noexcept(<expr>)'
  ...\proxy\proxy.h(506): note: while trying to match the argument list '(const std::in_place_type_t<pro::details::deep_ptr<Rectangle>>, Rectangle)'

By default, pro::facade<> specifies a move-only proxy, making Rectangle also move-only. This code won't compile because in pro::make_proxy<DrawableFacade>(rect), rect is passed by lvalue reference, pro::make_proxy() will try to copy the value, but Rectangle is not copiable.

There are two ways to fix the code:

  1. Change pro::make_proxy<DrawableFacade>(rect) to pro::make_proxy<DrawableFacade>(std::move(rect)), or
  2. Add static constexpr auto minimum_copyability = pro::constraint_level::nontrivial; into the body of struct DrawableFacade, to make pro::proxy<DrawableFacade> copiable.

Thank you for your quick reply. I was able to compile the example after adding your suggestion and also a default constructor to the Rectangle class.