title: Proxy object/reference getters vs setters?
body: <p>When I am designing a generic class, I am often in dilemma between the following design choices:</p>
  
  <pre><code>template&lt;class T&gt;
  class ClassWithSetter {
   public:
    T x() const; // getter/accessor for x
    void set_x(const T&amp; x);
    ...
  };
  // vs
  template&lt;class T&gt;
  class ClassWithProxy {
    struct Proxy {
      Proxy(ClassWithProxy&amp; c /*, (more args) */);
      Proxy&amp; operator=(const T&amp; x);  // allow conversion from T
      operator T() const;  // allow conversion to T
      // we disallow taking the address of the reference/proxy (see reasons below)
      T* operator&amp;() = delete;
      T* operator&amp;() const = delete;
      // more operators to delegate to T?
     private:
      ClassWithProxy&amp; c_;
    };
   public:
    T x() const; // getter
    Proxy x();  // this is a generalization of: T&amp; x();
    // no setter, since x() returns a reference through which x can be changed
    ...
  }; 
  </code></pre>
  
  <p>Notes:</p>
  
  <ul>
  <li>the reason why I return <code>T</code> instead of <code>const T&amp;</code> in <code>x()</code> and <code>operator T()</code> is because a reference to <code>x</code> might not be available from within the class if <code>x</code> is stored only <em>implicitly</em> (e.g. suppose <code>T = std::set&lt;int&gt;</code> but <code>x_</code> of type <code>T</code> is stored as <code>std::vector&lt;int&gt;</code>)</li>
  <li>suppose caching of Proxy objects and/or <code>x</code> is <em>not</em> allowed</li>
  </ul>
  
  <p>I am wondering what would be some scenarios in which one would prefer one approach versus the other, esp. in terms of:</p>
  
  <ul>
  <li>extensibility / generality</li>
  <li>efficiency</li>
  <li>developer's effort</li>
  <li>user's effort</li>
  </ul>
  
  <p>?</p>
  
  <p>You can assume that the compiler is smart enough to apply NRVO and fully inlines all the methods.</p>
  
  <p><strong>Current personal observations:</strong></p>
  
  <p>(This part is not relevant for answering the question; it just serves as a motivation and illustrates that sometimes one approach is better than the other.)</p>
  
  <p>One particular scenario in which the setter approach is problematic is as follows. Suppose you're implementing a container class with the following semantics:</p>
  
  <ul>
  <li><code>MyContainer&lt;T&gt;&amp;</code> (mutable, read-write) - allows modifying on both the container and its data
  implementation of the </li>
  <li><code>MyContainer&lt;const T&gt;&amp;</code> (mutable, read-only)  - allows modifying to the container but not its data</li>
  <li><code>const MyContainer&lt;T&gt;</code> (immutable, read-write) - allows modifying the data but not the container</li>
  <li><code>const MyContainer&lt;const T&gt;</code> (immutable, read-only) - no modifying to the container/data</li>
  </ul>
  
  <p>where by "container modifications" I mean operations like adding/removing elements. If I implement this naively with a setter approach:</p>
  
  <pre><code>template&lt;class T&gt;
  class MyContainer {
   public:
     void set(const T&amp; value, size_t index) const {  // allow on const MyContainer&amp;
       v_[index] = value;  // ooops,
       // what if the container is read-only (i.e., MyContainer&lt;const T&gt;)?
     }
     void add(const T&amp; value);  // disallow on const MyContainer&amp;
     ...
   private:
    mutable std::vector&lt;T&gt; v_;
  };
  </code></pre>
  
  <p>The problem could be mitigated by introducing a lot of boilerplate code that relies on SFINAE (e.g. by deriving from a specialized template helper which implements both versions of <code>set()</code>). However, a bigger problem is that this <em>brakes the common interface</em>, as we need to either:</p>
  
  <ul>
  <li>ensure that calling set() on an read-only container is a compile error</li>
  <li>provide a different semantics for the set() method for read-only containers</li>
  </ul>
  
  <p>On the other hand, while the Proxy-based approach works neatly:</p>
  
  <pre><code>template&lt;class T&gt;
  class MyContainer {
     typedef T&amp; Proxy;
   public:
     Proxy get(const T&amp; value, size_t index) const {  // allow on const MyContainer&amp;
       return v_[index];  // here we don't even need a const_cast, thanks to overloading
     }
     ...
  };
  </code></pre>
  
  <p>and the common interface and semantics is not broken.</p>
  
  <p>One difficulty I see with the proxy approach is supporting the <code>Proxy::operator&amp;()</code>
  because there might be no object of type <code>T</code> stored / a reference to available (see notes above). For example, consider:</p>
  
  <pre><code>T* ptr = &amp;x();
  </code></pre>
  
  <p>which cannot be supported unless <code>x_</code> is actually stored somewhere (either in the class itself or accessible through a (chain of) methods called on member variables), e.g.:</p>
  
  <pre><code>template&lt;class T&gt;
  T&amp; ClassWithProxy::Proxy::operator&amp;() {
    return &amp;c_.get_ref_to_x();
  }
  </code></pre>
  
  <p>Does that mean that the proxy object references are actually superior when <code>T&amp;</code> is available (i.e. <code>x_</code> is explicitly stored) as it allows for:</p>
  
  <ul>
  <li>batching/delaying updates (e.g. imagine the changes are propagated from the proxy class destructor)</li>
  <li>better control over caching
  ?</li>
  </ul>
  
  <p>(In that case, the dilemma is between <code>void set_x(const T&amp; value)</code> and <code>T&amp; x()</code>.)</p>
  
  <p>Edit: I changed the typos in constness of setters/accessors</p>