#include <utility>
enum access_flags {
readable = 1 << 0,
writeable = 1 << 1
};
template <typename ValueT>
class default_accessor {
public:
// Types.
typedef ValueT value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
// Constructors.
default_accessor(const_reference value_ref) : m_value_ref(value_ref)
{
// Do nothing.
}
// Accessors.
const_reference operator()() const noexcept
{
return m_value_ref;
}
private:
// Data.
const_reference m_value_ref;
};
template <typename ValueT>
class default_mutator {
public:
// Types.
typedef ValueT value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
// Constructors.
default_mutator(reference value_ref) : m_value_ref(value_ref)
{
// Do nothing.
}
// Mutators.
void operator()(const_reference value) noexcept
{
m_value_ref = value;
}
void operator()(value_type&& value) noexcept
{
m_value_ref = std::move(value);
}
private:
// Data.
reference m_value_ref;
};
template <typename ValueT, unsigned AccessFlags = readable | writeable, class Accessor = default_accessor<ValueT>,
class Mutator = default_mutator<ValueT>>
class property {
public:
// Types.
typedef ValueT value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef Accessor accessor_type;
typedef Mutator mutator_type;
// Constructors.
property() : m_accessor(m_value), m_mutator(m_value)
{
// Do nothing.
}
property(accessor_type accessor, mutator_type mutator) : m_accessor(accessor), m_mutator(mutator)
{
// Do nothing.
}
property(accessor_type accessor) : m_accessor(accessor), m_mutator(m_value)
{
// Do nothing.
}
property(mutator_type mutator) : m_accessor(m_value), m_mutator(mutator)
{
// Do nothing.
}
property(reference value_ref) : m_accessor(value_ref), m_mutator(value_ref)
{
// Do nothing.
}
// Accessors.
const_reference get() const noexcept
{
static_assert((AccessFlags & readable) == readable, "Can't read write-only property.");
return m_accessor();
}
const_reference get() noexcept
{
static_assert((AccessFlags & readable) == readable, "Can't read write-only property.");
return m_accessor();
}
// Mutators.
void set(const_reference value)
{
static_assert((AccessFlags & readable) == readable, "Can't write to read-only property.");
m_mutator(value);
}
void set(value_type&& value)
{
static_assert((AccessFlags & readable) == readable, "Can't write to read-only property.");
m_mutator(value);
}
property& operator=(const_reference rhs)
{
const property& lhs(*this);
lhs.set(rhs);
return lhs;
}
property& operator=(const property& rhs)
{
const property& lhs(*this);
lhs.set(rhs.get());
return lhs;
}
private:
// Data.
ValueT m_value;
accessor_type m_accessor;
mutator_type m_mutator;
};
#include <iostream>
/// Custom accessor.
class my_accessor {
public:
my_accessor(const int& value_ref, int& counter_ref) : m_value_ref(value_ref), m_counter_ref(counter_ref)
{
// Do nothing.
}
const int& operator()() noexcept
{
++m_counter_ref;
return m_value_ref;
}
private:
const int& m_value_ref;
int& m_counter_ref;
};
/// Example showing a read-only property with a custom accessor which increments a counter whenever the property is
/// accessed.
class foo {
public:
property<int, readable, my_accessor> readonly;
property<int, readable> times_accessed;
foo(int value) : m_readonly(value), m_times_accessed(0), readonly(my_accessor(m_readonly, m_times_accessed)),
times_accessed(m_times_accessed)
{
// Do nothing.
}
private:
int m_readonly;
int m_times_accessed;
};
int main()
{
foo object(5);
for (int i = 0; i < 5; ++i) {
std::cout << "Times accessed: " << object.times_accessed.get() << '\n';
int tmp = object.readonly.get();
}
std::cout << "Times accessed: " << object.times_accessed.get() << std::endl;
return 0;
}