Created
November 8, 2021 22:17
-
-
Save eyalroz/17ccfa26fb63c9385c1d2c4f943e59c9 to your computer and use it in GitHub Desktop.
A generic proxy class for replacing getters and setters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
#include <utility> | |
#ifndef CONSTEXPR_SINCE_CPP14 | |
# if __cplusplus >= 201402L | |
# define CONSTEXPR_SINCE_CPP14 constexpr | |
# else | |
# define CONSTEXPR_SINCE_CPP14 | |
# endif | |
#endif | |
template <typename Handle, typename Getter, typename Setter> | |
class proxy { | |
public: | |
using getter_return_type = decltype(std::declval<Getter>()(std::declval<Handle>()) ); | |
// Note: We assume the getter does not allow modifying the value. If it | |
// does - you don't need the proxy in the first place. But _asserting_ this | |
// is difficult. For example, suppose the getter returns an int*. Is the | |
// "actual" value an int, or an int*? We can't know that without introducing | |
// yet another type parameter. | |
using value_type = typename std::remove_reference<typename std::remove_cv<getter_return_type>::type>::type; | |
CONSTEXPR_SINCE_CPP14 | |
operator getter_return_type() const noexcept(noexcept(getter_)) | |
{ return getter_(handle_); } | |
CONSTEXPR_SINCE_CPP14 proxy& | |
operator=(const value_type& x) noexcept(noexcept(setter_)) | |
{ setter_(handle_, x); return *this; } | |
CONSTEXPR_SINCE_CPP14 proxy& | |
operator=(value_type&& x) noexcept(noexcept(setter_)) | |
{ setter_(handle_, std::move(x)); return *this; } | |
CONSTEXPR_SINCE_CPP14 | |
proxy(Handle handle, const Getter& getter, const Setter& setter) noexcept | |
: handle_(handle), getter_(getter), setter_(setter) { } | |
protected: | |
const Handle handle_; | |
// Note: The handle is constant, not the referred-to element. So, _don't_ | |
// use a `T&` as your Handle, or you'll be in trouble | |
const Getter& getter_; | |
const Setter& setter_; | |
// Note: Attempts to use just plain Getter and Setter as the types here | |
// don't work when Getter/Setter are function types | |
}; | |
// Allows for template argument deduction during "construction" - before C++17 | |
template <typename Handle, typename Getter, typename Setter> | |
CONSTEXPR_SINCE_CPP14 proxy<Handle, Getter, Setter> | |
make_proxy(const Handle& handle, const Getter& getter, const Setter& setter) noexcept | |
{ | |
return proxy<Handle, Getter, Setter>(handle, getter, setter); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment