I have made a facility to perform operator=
dispatching to a member setter function. The purpose is to enable accessing members (like using object.member = value;
) while at the same time respecting encapsulation.
My implementation looks like this:
#include <iostream>
#define OPEQ_SETTER_GETTER( OwnerType, Type, Function, Name ) \
accessor< Type, OwnerType, decltype(&OwnerType::Function) > Name = \
accessor< Type, OwnerType, decltype(&OwnerType::Function) >(this, &OwnerType::Function); \
friend class accessor< Type, OwnerType, decltype(&OwnerType::Function) >;
// A generic accesor class
template <typename T, class Owner, class Setter> struct accessor {
accessor ( Owner* o, Setter &&f ): owner( o ), setter( f ) { }
accessor &operator=( const T &value ) { setter( owner, data, value ); return *this; }
operator T() const { return data; }
private:
Owner *owner;
Setter setter;
T data;
};
// An example of applying the idiom
class example
{
private:
static void setx( example *this_handle, double &data, const double &value )
{
std::cout << "Setting data to: " << value << '\n';
this_handle->another_member = 85656;
std::cout << "another_member is: " << this_handle->another_member << '\n';
data = value;
}
std::size_t another_member = 0;
public:
example( ) {}
OPEQ_SETTER_GETTER( example, double, setx, x );
// Will expand to:
//accessor< double, example, decltype(&example::setx) > x =
// accessor< double, example, decltype(&example::setx) >(this, &example::setx);
//friend class accessor< double, example, decltype(&example::setx) >;
};
int main()
{
example e;
e.x = 2*3.14159;
std::cout << "New value: " << e.x << '\n';
return 0;
}
The questions I have questions are:
- Does anybody see any issues with the above?
- Does anybody have any suggestions in implementing this without using the preprocessor and still keep the interface similarly compact?