title: Zero-cost properties with data member syntax
body: <p>I have (re?)invented this approach to zero-cost properties with data member syntax. By this I mean that the user can write:</p>
  
  <pre><code>some_struct.some_member = var;
  var = some_struct.some_member;
  </code></pre>
  
  <p>and these member accesses redirect to member functions with zero overhead.</p>
  
  <p>While initial tests show that the approach does work in practice, I'm far from sure that it is free from undefined behaviour. Here's the simplified code that illustrates the approach:</p>
  
  <pre><code>template &lt;class Owner, class Type, Type&amp; (Owner::*accessor)()&gt;
  struct property {
      operator Type&amp;() {
          Owner* optr = reinterpret_cast&lt;Owner*&gt;(this);
          return (optr-&gt;*accessor)();
      }
      Type&amp; operator= (const Type&amp; t) {
          Owner* optr = reinterpret_cast&lt;Owner*&gt;(this);
          return (optr-&gt;*accessor)() = t;
      }
  };
  
  union Point
  {
      int&amp; get_x() { return xy[0]; }
      int&amp; get_y() { return xy[1]; }
      std::array&lt;int, 2&gt; xy;
      property&lt;Point, int, &amp;Point::get_x&gt; x;
      property&lt;Point, int, &amp;Point::get_y&gt; y;
  };
  </code></pre>
  
  <p>The test driver demonstrates that the approach works and it is indeed zero-cost (properties occupy no additional memory):</p>
  
  <pre><code>int main()
  {
      Point m;
      m.x = 42;
      m.y = -1;
  
      std::cout &lt;&lt; m.xy[0] &lt;&lt; " " &lt;&lt; m.xy[1] &lt;&lt; "\n";
      std::cout &lt;&lt; sizeof(m) &lt;&lt; " " &lt;&lt; sizeof(m.x) &lt;&lt; "\n";
  }
  </code></pre>
  
  <p>Real code is a bit more complicated but the gist of the approach is here. It is based on using a union of real data (<code>xy</code> in this example) and empty property objects. (Real data must be a standard layout class for this to work).</p>
  
  <p>The union is needed because otherwise properties needlessly occupy memory, despite being empty.</p>
  
  <p>Why do I think there's no UB here? The standard permits accessing the common initial sequence of standard-layout union members. Here, the common initial sequence is empty. Data members of <code>x</code> and <code>y</code> are not accessed at all, as there are no data members. My reading of the standard indicate that this is allowed. <code>reinterpret_cast</code> should be OK because we are casting a union member to its containing union, and these are pointer-interconvertible.</p>
  
  <p>Is this indeed allowed by the standard, or I'm missing some UB here?</p>