out.h 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. #pragma once
  2. #include <type_traits>
  3. #include <utility>
  4. #include <variant>
  5. namespace jvalidate::detail {
  6. template <typename T> class out;
  7. constexpr struct discard_out_t {
  8. } discard_out;
  9. template <typename T> class out {
  10. private:
  11. T * ref_ = nullptr;
  12. public:
  13. out() = default;
  14. out(discard_out_t) {}
  15. out(T & ref) : ref_(&ref) {}
  16. explicit operator bool() const { return ref_; }
  17. template <typename U>
  18. requires std::is_constructible_v<T, U>
  19. void operator=(U && val) {
  20. if (ref_) {
  21. *ref_ = std::forward<U>(val);
  22. }
  23. return *this;
  24. }
  25. };
  26. template <typename T>
  27. requires(std::is_same_v<T, std::decay_t<T>>) class inout {
  28. private:
  29. std::variant<T, T *> ref_;
  30. public:
  31. inout(T && value) : ref_(std::move(value)) {}
  32. inout(T & ref) : ref_(&ref) {}
  33. operator T const &() const {
  34. struct {
  35. T const & operator()(T const & in) const { return in; }
  36. T const & operator()(T * in) const { return *in; }
  37. } visitor;
  38. return std::visit(visitor, ref_);
  39. }
  40. template <typename U>
  41. requires std::is_constructible_v<T, U> T const & operator=(U && val) {
  42. struct {
  43. U && val;
  44. void operator()(T & in) const { in = std::forward<U>(val); }
  45. void operator()(T * in) const { *in = std::forward<U>(val); }
  46. } visitor{std::forward<U>(val)};
  47. std::visit(visitor, ref_);
  48. return static_cast<T const &>(*this);
  49. }
  50. };
  51. }