(There is now a 2nd version of this code)
Have you ever written proxy objects, instead of using a setter and a getter method? In that case, I'm interested in your opinion on the following design for a templated proxy:
#include <type_traits>
#include <utility>
template <typename Handle, typename Getter, typename Setter>
class proxy {
public:
using value_type = decltype(std::declval<Getter>()(std::declval<Handle>()) );
operator value_type() const { return getter_(handle_); }
proxy& operator=(const value_type& x) { setter_(handle_, x); return *this; }
proxy& operator=(const value_type&& x) { setter_(handle_, x); return *this; }
proxy(Handle handle, const Getter& getter, const Setter& setter) :
handle_(handle), getter_(getter), setter_(setter) { }
protected:
const Handle handle_;
const Getter& getter_;
const Setter& setter_;
};
// Allows for template argument deduction during "construction" - before C++17
template <typename Handle, typename Getter, typename Setter>
proxy<Handle, Getter, Setter>
make_proxy(const Handle& handle, const Getter& getter, const Setter& setter)
{
return proxy<Handle, Getter, Setter>(handle, getter, setter);
}
Simple example of use:
int my_getter(int *x) { return *x; }
void my_setter(int *x, int val ) { *x = val; }
class foo {
public:
auto datum() {
return make_proxy(&x, my_getter, my_setter);
}
protected:
int x { 123 };
};
int main() {
foo my_foo;
my_foo.datum() = 456;
return my_foo.datum();
}
(in this example, the getter and setter aren't really necessary because the "raw" field exists. But think about opqaue operating-system resources, or individual bits in a bit-container etc.)
Other than general comments on the design - I was also thinking about the choice of template parameters. I might be able to drop the Handle type - if I could manager to extract that information from Getter
; or alternatively, I could add the value_type as a template parameter - as otherwise it could be confusing to the person seeing an instantiation to understand what type they should actually use with the proxy.
Also, I was wondering whether I should provide comparators (seeing how this class is convertible to value_type
's, which we should be able to compare).
Finally, I was also thinking of not keeping the getter_
and setter_
at all, and only instantiating them on use. But I'm worried this will make the class too convoluted to write and/or use.
Note: This needs to be C++11-compatible.