<xstd/misc/concepts/proxy_reference.hpp>¶
xstd::proxy_reference¶
template<class R>
concept proxy_reference =
requires(R& ref) { { &ref } -> proxy_semi_iterator; } and
same_as<iter_reference_t<decltype(&declval<R&>())>, R> and
indirectly_writable<decltype(&declval<R&>()), iter_value_t<decltype(&declval<R&>())>>;
A proxy whose address is a semi-iterator dereferencing back to it, and which writes through to its value when
const.
Models¶
- A library's bit reference models it exactly where the library gives it an
operator&and an assignment throughconst. - A read-only proxy, such as
vector<bool>::const_reference, does not. - A class that converts without the round trip does not.
- An address that dereferences to the value rather than back to the proxy is turned away.
Notes¶
- A type that models it is a semi-reference for the value type its address names, and its address models
proxy_iterator. - It does not subsume
proxy_semi_reference<R, V>, whoseVthe caller names: overloads constrained on each are ambiguous for a type that satisfies both, andand (not proxy_reference<R>)on the weaker one resolves them.
Example¶
#include <xstd/misc/concepts/proxy_reference.hpp> // proxy_reference
#include <cstddef> // ptrdiff_t
#include <iostream> // boolalpha, cout
#include <iterator> // iter_value_t
#include <vector> // vector
enum class shade : unsigned char
{
light,
dark
};
class shade_iterator;
// One shade, kept as one bit of a word, and read and written through this proxy.
class shade_reference
{
unsigned* m_word;
unsigned m_bit;
public:
[[nodiscard]] constexpr shade_reference(unsigned* word, unsigned bit) noexcept
: m_word(word)
, m_bit(bit)
{}
[[nodiscard]] constexpr explicit(false) operator shade() const noexcept
{
return static_cast<shade>((*m_word >> m_bit) & 1U);
}
// Writes through a const proxy, as a const language reference writes to what it refers to.
constexpr auto operator=(shade value) const noexcept
-> shade_reference const&
{
*m_word = (*m_word & ~(1U << m_bit)) | (static_cast<unsigned>(value) << m_bit);
return *this;
}
// The address of a shade is an iterator that yields this proxy back.
[[nodiscard]] constexpr auto operator&() const noexcept
-> shade_iterator;
};
class shade_iterator
{
unsigned* m_word;
unsigned m_bit;
public:
using value_type = shade;
using difference_type = std::ptrdiff_t;
[[nodiscard]] constexpr shade_iterator(unsigned* word, unsigned bit) noexcept
: m_word(word)
, m_bit(bit)
{}
[[nodiscard]] constexpr auto operator*() const noexcept
-> shade_reference
{
return shade_reference(m_word, m_bit);
}
};
constexpr auto shade_reference::operator&() const noexcept
-> shade_iterator
{
return shade_iterator(m_word, m_bit);
}
[[nodiscard]] constexpr auto name(shade s) noexcept
-> char const*
{
return s == shade::dark ? "dark" : "light";
}
// Resets what a language reference refers to.
template<class T>
auto reset(T& value) -> void
{
value = T();
}
// Resets what a proxy reference stands for: taken by value, it still writes through, and its address names the value.
template<xstd::proxy_reference R>
auto reset(R ref) -> void
{
ref = std::iter_value_t<decltype(&ref)>();
}
auto main() -> int
{
auto plain = shade::dark;
auto word = 0b11U;
reset(plain);
reset(*shade_iterator(&word, 1));
std::cout << "plain is " << name(plain) << ", the packed shades are " << name(*shade_iterator(&word, 0)) << " and " << name(*shade_iterator(&word, 1)) << '\n';
std::cout << std::boolalpha;
std::cout << "proxy_reference<shade_reference> is " << xstd::proxy_reference<shade_reference> << '\n';
std::cout << "proxy_reference<shade&> is " << xstd::proxy_reference<shade&> << '\n';
std::cout << "proxy_reference<vector<bool>::const_reference> is " << xstd::proxy_reference<std::vector<bool>::const_reference> << '\n';
}
Output:
plain is light, the packed shades are dark and light
proxy_reference<shade_reference> is true
proxy_reference<shade&> is false
proxy_reference<vector<bool>::const_reference> is false
See also¶
| Entity | Relation |
|---|---|
proxy_semi_reference |
the weaker concept, with the value type named by the caller |
proxy_iterator |
what its address models |
to_underlying |
takes a proxy reference to an enumerator |